gzip 网站网络营销案例100例
- 作者: 多梦笔记
- 时间: 2026年02月16日 16:53
当前位置: 首页 > news >正文
gzip 网站,网络营销案例100例,公众号登录入口在哪,基本的网络架构一、服务调用流程 服务在订阅过程中#xff0c;把notify 过来的urls 都转成了invoker#xff0c;不知道大家是否还记得前面的rpc 过程#xff0c;protocol也是在服务端和消费端各连接子一个invoker#xff0c;如下图#xff1a; 这张图主要展示rpc 主流程#xff0c;消费…一、服务调用流程 服务在订阅过程中把notify 过来的urls 都转成了invoker不知道大家是否还记得前面的rpc 过程protocol也是在服务端和消费端各连接子一个invoker如下图 这张图主要展示rpc 主流程消费端想要远程调用时他是调用invoker#invoke方法;服务端收到网络请求时也是直接触发invoker#invoke 方法。Dubbo 设计invoker 实体的初衷就是想要统一操作无论你要做什么方法调用都请使用invoker 来包装后使用invoker#invoke来调用这个动作简化来看rpc 过程即是如此 消费端invoker#invoke ——网络—-服务端invoker#invoke—ref 服务 上面的链路是个简化的路径但在实际的dubbo 调用中此链条可能会有局部的多层嵌套如 消费端invoker#invoke ——容错策略—网络—-服务端invoker#invoke—ref服务 那么此时要重新定义链条吗那不是个好主意。Dubbo 的做法是这样将容错策略也包装成invoker 对象 FailfastClusterInvoker#invoke—protocolInvoker.invoke–网络—-服务端invoker#invoke—ref 服务 依次类推dubbo 内部有非常多的invoker 包装类它们层层嵌套但rpc流程不关心细节只傻瓜式地调用其invoke 方法剩下的逻辑自会传递到最后一个invoker 进行网络调用。 服务引入时最终又对生成invoker的做了一层代理所以熟悉动态代理的知道当执行服务调用时最先执行到的是InvokerInvocationHandler#invoke方法 public T T getProxy(InvokerT invoker, Class?[] interfaces) {try {return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));} catch (Throwable fromJavassist) {// try fall back to JDK proxy factorytry {T proxy jdkProxyFactory.getProxy(invoker, interfaces);logger.error(Failed to generate proxy by Javassist failed. Fallback to use JDK proxy success. Interfaces: Arrays.toString(interfaces), fromJavassist);return proxy;} catch (Throwable fromJdk) {logger.error(Failed to generate proxy by Javassist failed. Fallback to use JDK proxy is also failed. Interfaces: Arrays.toString(interfaces) Javassist Error., fromJavassist);logger.error(Failed to generate proxy by Javassist failed. Fallback to use JDK proxy is also failed. Interfaces: Arrays.toString(interfaces) JDK Error., fromJdk);throw fromJavassist;}} } 二、Dubbo过滤器链 Filter过滤器在很多框架中都有使用过这个概念基本上的作用都是类似的在请求处理前或者处理后做一些通用的逻辑而且Filter 可以有多个支持层层嵌套。 Dubbo 的Filter 实现入口是在ProtocolFilterWrapper因为ProtocolFilterWrapper 是Protocol 的包装类所以会在SPI 加载的Extension 的时候被自动包装进来。当然filter 要发挥作用必定还是要 在嵌入到RPC 的调用线中你马上应该反应过来嵌入的办法就是包装成invoker ProtocolFilterWrapper 作为包装类会成为其它protocol 的修饰加强外层。因此protocol 的export 和refer 方法首先是调用ProtocolFilterWrapper 类的。 暴露服务代码 public T ExporterT export(InvokerT invoker) throws RpcException {if (UrlUtils.isRegistry(invoker.getUrl())) {return protocol.export(invoker);}FilterChainBuilder builder getFilterChainBuilder(invoker.getUrl());return protocol.export(builder.buildInvokerChain(invoker, SERVICE_FILTER_KEY, CommonConstants.PROVIDER)); } 引入服务代码 public T InvokerT refer(ClassT type, URL url) throws RpcException {if (UrlUtils.isRegistry(url)) {return protocol.refer(type, url);}FilterChainBuilder builder getFilterChainBuilder(url);return builder.buildInvokerChain(protocol.refer(type, url), REFERENCE_FILTER_KEY, CommonConstants.CONSUMER); } 可以看到两者原来的invoker 对象都由builder#buildInvokerChain 做了一层包装。 来看一下filterChain 的逻辑 public T InvokerT buildInvokerChain(final InvokerT originalInvoker, String key, String group) {InvokerT last originalInvoker;URL url originalInvoker.getUrl();//……(省略部分代码)if (!CollectionUtils.isEmpty(filters)) {for (int i filters.size() - 1; i 0; i–) {final Filter filter filters.get(i);final InvokerT next last;last new CopyOfFilterChainNode(originalInvoker, next, filter);}return new CallbackRegistrationInvoker(last, filters);}return last; } 逻辑较为简单 1、所有filter 包装进invoker 对象中invoke 方法直接调对应的filter#invoke。 2、filter 对象首尾相联前一个filter#invoke 参数传入后一个filter 的invoker对象 3、最后一个filter.invoke 参数中直接传原始的invoker 对象 4、filter 的所有获取按扩展点方式得到 ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group); 所以这里创建RpcInvocation执行invoke方法中间会经过一系列过滤器filter#invoke后就会来到FailoverClusterInvoker#invoke方法中。 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {RpcInvocation rpcInvocation new RpcInvocation(serviceModel, method, invoker.getInterface().getName(), protocolServiceKey, args);String serviceKey url.getServiceKey();rpcInvocation.setTargetServiceUniqueName(serviceKey);// invoker.getUrl() returns consumer url.RpcServiceContext.setRpcContext(url);if (serviceModel instanceof ConsumerModel) {rpcInvocation.put(Constants.CONSUMER_MODEL, serviceModel);rpcInvocation.put(Constants.METHOD_MODEL, ((ConsumerModel) serviceModel).getMethodModel(method));}if (ProfilerSwitch.isEnableSimpleProfiler()) {ProfilerEntry parentProfiler Profiler.getBizProfiler();ProfilerEntry bizProfiler;boolean containsBizProfiler false;if (parentProfiler ! null) {containsBizProfiler true;bizProfiler Profiler.enter(parentProfiler, Receive request. Client invoke begin.);} else {bizProfiler Profiler.start(Receive request. Client invoke begin.);}rpcInvocation.put(Profiler.PROFILER_KEY, bizProfiler);try {return invoker.invoke(rpcInvocation).recreate();} finally {Profiler.release(bizProfiler);if (!containsBizProfiler) {int timeout;Object timeoutKey rpcInvocation.getObjectAttachmentWithoutConvert(TIMEOUT_KEY);if (timeoutKey instanceof Integer) {timeout (Integer) timeoutKey;} else {timeout url.getMethodPositiveParameter(methodName, TIMEOUT_KEY, DEFAULT_TIMEOUT);}long usage bizProfiler.getEndTime() - bizProfiler.getStartTime();if ((usage / (1000_000L * ProfilerSwitch.getWarnPercent())) timeout) {StringBuilder attachment new StringBuilder();for (Map.EntryString, Object entry : rpcInvocation.getObjectAttachments().entrySet()) {attachment.append(entry.getKey()).append().append(entry.getValue()).append(;\n);}logger.warn(String.format([Dubbo-Consumer] execute service %s#%s cost %d.%06d ms, this invocation almost (maybe already) timeout\n invocation context:\n%s thread info: \n%s,protocolServiceKey, methodName, usage / 1000_000, usage % 1000_000,attachment, Profiler.buildDetail(bizProfiler)));}}}}return invoker.invoke(rpcInvocation).recreate(); } 下面代码主要做了三件事情 1、ListInvokerT invokers list(invocation);获取当前服务可执行的所有invokers数量。 2、LoadBalance loadbalance initLoadBalance(invokers, invocation);利用SPI机制获取当前负载均衡策略LoadBalance。 3、doInvoke(invocation, invokers, loadbalance)。负载均衡策略会选择出一个invoker然后执行。 public Result invoke(final Invocation invocation) throws RpcException {checkWhetherDestroyed();InvocationProfilerUtils.enterDetailProfiler(invocation, () - Router route.);ListInvokerT invokers list(invocation);InvocationProfilerUtils.releaseDetailProfiler(invocation);LoadBalance loadbalance initLoadBalance(invokers, invocation);RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);InvocationProfilerUtils.enterDetailProfiler(invocation, () - Cluster this.getClass().getName() invoke.);try {return doInvoke(invocation, invokers, loadbalance);} finally {InvocationProfilerUtils.releaseDetailProfiler(invocation);} } 我们知道一个服务的invokers都存在了registryDirectory中 protected ListInvokerT list(Invocation invocation) throws RpcException {return getDirectory().list(invocation); }public ListInvokerT list(Invocation invocation) throws RpcException {if (destroyed) {throw new RpcException(Directory already destroyed .url: getUrl());}BitListInvokerT availableInvokers;// use clone to avoid being modified at doList().if (invokersInitialized) {availableInvokers validInvokers.clone();} else {availableInvokers invokers.clone();}ListInvokerT routedResult doList(availableInvokers, invocation);return Collections.unmodifiableList(routedResult); } 然后回利用路由规则调用routerChain.route方法路由出正确的invokers具体路由功能后面再讲解。 public ListInvokerT doList(BitListInvokerT invokers, Invocation invocation) {if (forbidden shouldFailFast) {// 1. No service provider 2. Service providers are disabledthrow new RpcException(RpcException.FORBIDDEN_EXCEPTION, No provider available from registry getUrl().getAddress() for service getConsumerUrl().getServiceKey() on consumer NetUtils.getLocalHost() use dubbo version Version.getVersion() , please check status of providers(disabled, not registered or in blacklist).);}if (multiGroup) {return this.getInvokers();}try {// Get invokers from cache, only runtime routers will be executed.ListInvokerT result routerChain.route(getConsumerUrl(), invokers, invocation);return result null ? BitList.emptyList() : result;} catch (Throwable t) {logger.error(Failed to execute router: getUrl() , cause: t.getMessage(), t);return BitList.emptyList();} } 三、负载均衡 下面这行代码会获取到当前配置的负载均衡策略 LoadBalance loadbalance initLoadBalance(invokers, invocation) 最终也是利用SPI机制加载ExtensionLoader#getExtension(DEFAULT_LOADBALANCE) 而默认的负载均衡策略可以看到是随机。 protected LoadBalance initLoadBalance(ListInvokerT invokers, Invocation invocation) {ApplicationModel applicationModel ScopeModelUtil.getApplicationModel(invocation.getModuleModel());if (CollectionUtils.isNotEmpty(invokers)) {return applicationModel.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl().getMethodParameter(RpcUtils.getMethodName(invocation), LOADBALANCE_KEY, DEFAULT_LOADBALANCE));} else {return applicationModel.getExtensionLoader(LoadBalance.class).getExtension(DEFAULT_LOADBALANCE);} } 然后继续执行来到FailoverClusterInvoker#doInvoke方法首先获取执行次数for循环进行调用只要不是正常返回就再试一次默认的len为3次这也是dubbo基础常识在这里可以体现出来。 然后调用下面的select方法获取到一个invoker最终会执行到loadBalance#doSelect方法当然不同的负载均衡策略获取invoker的算法也不同这里应用了模板模式。 public Result doInvoke(Invocation invocation, final ListInvokerT invokers, LoadBalance loadbalance) throws RpcException {ListInvokerT copyInvokers invokers;checkInvokers(copyInvokers, invocation);String methodName RpcUtils.getMethodName(invocation);int len calculateInvokeTimes(methodName);// retry loop.RpcException le null; // last exception.ListInvokerT invoked new ArrayListInvokerT(copyInvokers.size()); // invoked invokers.SetString providers new HashSetString(len);for (int i 0; i len; i) {//Reselect before retry to avoid a change of candidate invokers.//NOTE: if invokers changed, then invoked also lose accuracy.if (i 0) {checkWhetherDestroyed();copyInvokers list(invocation);// check againcheckInvokers(copyInvokers, invocation);}InvokerT invoker select(loadbalance, invocation, copyInvokers, invoked);invoked.add(invoker);RpcContext.getServiceContext().setInvokers((List) invoked);boolean success false;try {Result result invokeWithContext(invoker, invocation);if (le ! null logger.isWarnEnabled()) {logger.warn(Although retry the method methodName in the service getInterface().getName() was successful by the provider invoker.getUrl().getAddress() , but there have been failed providers providers ( providers.size() / copyInvokers.size() ) from the registry directory.getUrl().getAddress() on the consumer NetUtils.getLocalHost() using the dubbo version Version.getVersion() . Last error is: le.getMessage(), le);}success true;return result;} catch (RpcException e) {if (e.isBiz()) { // biz exception.throw e;}le e;} catch (Throwable e) {le new RpcException(e.getMessage(), e);} finally {if (!success) {providers.add(invoker.getUrl().getAddress());}}}throw new RpcException(le.getCode(), Failed to invoke the method methodName in the service getInterface().getName() . Tried len times of the providers providers ( providers.size() / copyInvokers.size() ) from the registry directory.getUrl().getAddress() on the consumer NetUtils.getLocalHost() using the dubbo version Version.getVersion() . Last error is: le.getMessage(), le.getCause() ! null ? le.getCause() : le); } RandomLoadBalance#doSelect方法具体代码逻辑不做详细解释主要是根据服务设置的权重进行随机选取权重大的被选中的概率就会大一点有兴趣的可以断点研究下这里只是让大家了解负载均衡就是这么简单的东西我们也可以创建一个自己的负载均衡策略只需要继承AbstractLoadBalance并实现自己的doSelect方法然后还需要配置指定用我们所写的负载均衡策略从代码流程上可以看出来dubbo的负载均衡策略其实是客户端负载均衡。 protected T InvokerT doSelect(ListInvokerT invokers, URL url, Invocation invocation) {// Number of invokersint length invokers.size();if (!needWeightLoadBalance(invokers,invocation)){return invokers.get(ThreadLocalRandom.current().nextInt(length));}// Every invoker has the same weight?boolean sameWeight true;// the maxWeight of every invokers, the minWeight 0 or the maxWeight of the last invokerint[] weights new int[length];// The sum of weightsint totalWeight 0;for (int i 0; i length; i) {int weight getWeight(invokers.get(i), invocation);// SumtotalWeight weight;// save for later useweights[i] totalWeight;if (sameWeight totalWeight ! weight * (i 1)) {sameWeight false;}}if (totalWeight 0 !sameWeight) {// If (not every invoker has the same weight at least one invokers weight0), select randomly based on totalWeight.int offset ThreadLocalRandom.current().nextInt(totalWeight);// Return a invoker based on the random value.for (int i 0; i length; i) {if (offset weights[i]) {return invokers.get(i);}}}// If all invokers have the same weight value or totalWeight0, return evenly.return invokers.get(ThreadLocalRandom.current().nextInt(length)); } 那么dubbo中已经支持的负载均衡策略也有很多依次是ConsistentHashLoadBalance(一次性哈希)LeastActiveLoadBalance(最少活跃数)RandomLoadBalance(按照权重随机)RoundRobinLoadBalance(轮训)ShortestResponseLoadBalance(最短响应策略)不过生产环境中权重策略跟轮训策略是使用的最多的两种负载均衡方式。 四、集群容错 集群容错的实现方式其实在生成invoker的时候已经看到了dubbo会将生成的invoker最外层在包装一层ClusterInvoker这里又利用到了一种设计模式叫做装饰者模式。因为远程服务调用过程总肯定会先执行到ClusterInvoker#doInvoke方法那么每个容错ClusterInvoker实现类会按照自己的方式去执行当然我们也能继承AbstractClusterInvoker方法然后实现doInvoke方法然后配置自己的集群容错策略所以这个功能跟负载均衡一样简单。 Dubbo为应对不同的业务场景和需求提供了以下几种集群容错策略具体源码有兴趣的可以单独研究
- FailoverClusterInvoker默认 失败一次自动切换自动重试其他invoker默认三次。适用于读操作多、对实时性要求不高的场景。 2. Failfast 快速失败立即报错只发起一次调用。适用于非幂等性操作或实时性要求极高的场景。 3. Failsafe 失败安全出现异常时直接忽略。适用于对结果不敏感的操作如日志记录。 4. Failback 失败自动恢复记录失败请求定时重发。适用于可以异步处理且对实时性要求不高的操作。 5. Forking 并行调用多个服务器只要一个成功即返回。注意提高响应速度的同时需注意资源消耗和并行度控制。 6. Broadcast 广播调用所有服务提供者任一报错即报错。适用于需要全局一致性的场景如全局缓存更新。 选择合适的集群容错策略对于优化Dubbo应用的性能和可靠性至关重要。 到此Dubbo的服务调用过程讲解完毕。
- 上一篇: gta5资产网站正在建设网站维护推广怎么做
- 下一篇: h5互动网站建设公司网站域名cn和com
相关文章
-
gta5资产网站正在建设网站维护推广怎么做
gta5资产网站正在建设网站维护推广怎么做
- 站长
- 2026年02月16日
-
gps定位网站建设淄博网站app
gps定位网站建设淄博网站app
- 站长
- 2026年02月16日
-
go语言做网站网页制作软件排行榜
go语言做网站网页制作软件排行榜
- 站长
- 2026年02月16日
-
h5互动网站建设公司网站域名cn和com
h5互动网站建设公司网站域名cn和com
- 站长
- 2026年02月16日
-
h5可以做网站么十堰网站建设公司
h5可以做网站么十堰网站建设公司
- 站长
- 2026年02月16日
-
h5旅游网站开发企业管理软件erp
h5旅游网站开发企业管理软件erp
- 站长
- 2026年02月16日
