dubbo 集群容错源码
1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package com.alibaba.dubbo.rpc.cluster.support; 18 19 import com.alibaba.dubbo.common.Constants; 20 import com.alibaba.dubbo.common.Version; 21 import com.alibaba.dubbo.common.logger.Logger; 22 import com.alibaba.dubbo.common.logger.LoggerFactory; 23 import com.alibaba.dubbo.common.utils.NetUtils; 24 import com.alibaba.dubbo.rpc.Invocation; 25 import com.alibaba.dubbo.rpc.Invoker; 26 import com.alibaba.dubbo.rpc.Result; 27 import com.alibaba.dubbo.rpc.RpcContext; 28 import com.alibaba.dubbo.rpc.RpcException; 29 import com.alibaba.dubbo.rpc.cluster.Directory; 30 import com.alibaba.dubbo.rpc.cluster.LoadBalance; 31 32 import java.util.ArrayList; 33 import java.util.HashSet; 34 import java.util.List; 35 import java.util.Set; 36 37 /** 38 * When invoke fails, log the initial error and retry other invokers (retry n times, which means at most n different invokers will be invoked) 39 * Note that retry causes latency. 40 * <p> 41 * <a href="http://en.wikipedia.org/wiki/Failover">Failover</a> 42 * 43 */ 44 public class FailoverClusterInvoker<T> extends AbstractClusterInvoker<T> { 45 46 private static final Logger logger = LoggerFactory.getLogger(FailoverClusterInvoker.class); 47 48 public FailoverClusterInvoker(Directory<T> directory) { 49 super(directory); 50 } 51 52 @Override 53 @SuppressWarnings({"unchecked", "rawtypes"}) 54 public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { 55 List<Invoker<T>> copyinvokers = invokers; 56 checkInvokers(copyinvokers, invocation); 57 int len = getUrl().getMethodParameter(invocation.getMethodName(), Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1; 58 if (len <= 0) { 59 len = 1; 60 } 61 // retry loop. 62 RpcException le = null; // last exception. 63 List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyinvokers.size()); // invoked invokers. 64 Set<String> providers = new HashSet<String>(len); 65 for (int i = 0; i < len; i++) { 66 //Reselect before retry to avoid a change of candidate `invokers`. 67 //NOTE: if `invokers` changed, then `invoked` also lose accuracy. 68 if (i > 0) { 69 checkWhetherDestroyed(); 70 copyinvokers = list(invocation); 71 // check again 72 checkInvokers(copyinvokers, invocation); 73 } 74 Invoker<T> invoker = select(loadbalance, invocation, copyinvokers, invoked); 75 invoked.add(invoker); 76 RpcContext.getContext().setInvokers((List) invoked); 77 try { 78 Result result = invoker.invoke(invocation); 79 if (le != null && logger.isWarnEnabled()) { 80 logger.warn("Although retry the method " + invocation.getMethodName() 81 + " in the service " + getInterface().getName() 82 + " was successful by the provider " + invoker.getUrl().getAddress() 83 + ", but there have been failed providers " + providers 84 + " (" + providers.size() + "/" + copyinvokers.size() 85 + ") from the registry " + directory.getUrl().getAddress() 86 + " on the consumer " + NetUtils.getLocalHost() 87 + " using the dubbo version " + Version.getVersion() + ". Last error is: " 88 + le.getMessage(), le); 89 } 90 return result; 91 } catch (RpcException e) { 92 if (e.isBiz()) { // biz exception. 93 throw e; 94 } 95 le = e; 96 } catch (Throwable e) { 97 le = new RpcException(e.getMessage(), e); 98 } finally { 99 providers.add(invoker.getUrl().getAddress()); 100 } 101 } 102 throw new RpcException(le != null ? le.getCode() : 0, "Failed to invoke the method " 103 + invocation.getMethodName() + " in the service " + getInterface().getName() 104 + ". Tried " + len + " times of the providers " + providers 105 + " (" + providers.size() + "/" + copyinvokers.size() 106 + ") from the registry " + directory.getUrl().getAddress() 107 + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version " 108 + Version.getVersion() + ". Last error is: " 109 + (le != null ? le.getMessage() : ""), le != null && le.getCause() != null ? le.getCause() : le); 110 } 111 112 }
1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package com.alibaba.dubbo.rpc.cluster.support; 18 19 import com.alibaba.dubbo.common.Version; 20 import com.alibaba.dubbo.common.utils.NetUtils; 21 import com.alibaba.dubbo.rpc.Invocation; 22 import com.alibaba.dubbo.rpc.Invoker; 23 import com.alibaba.dubbo.rpc.Result; 24 import com.alibaba.dubbo.rpc.RpcException; 25 import com.alibaba.dubbo.rpc.cluster.Directory; 26 import com.alibaba.dubbo.rpc.cluster.LoadBalance; 27 28 import java.util.List; 29 30 /** 31 * Execute exactly once, which means this policy will throw an exception immediately in case of an invocation error. 32 * Usually used for non-idempotent write operations 33 * 34 * <a href="http://en.wikipedia.org/wiki/Fail-fast">Fail-fast</a> 35 * 36 */ 37 public class FailfastClusterInvoker<T> extends AbstractClusterInvoker<T> { 38 39 public FailfastClusterInvoker(Directory<T> directory) { 40 super(directory); 41 } 42 43 @Override 44 public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { 45 checkInvokers(invokers, invocation); 46 Invoker<T> invoker = select(loadbalance, invocation, invokers, null); 47 try { 48 return invoker.invoke(invocation); 49 } catch (Throwable e) { 50 if (e instanceof RpcException && ((RpcException) e).isBiz()) { // biz exception. 51 throw (RpcException) e; 52 } 53 throw new RpcException(e instanceof RpcException ? ((RpcException) e).getCode() : 0, "Failfast invoke providers " + invoker.getUrl() + " " + loadbalance.getClass().getSimpleName() + " select from all providers " + invokers + " for service " + getInterface().getName() + " method " + invocation.getMethodName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e.getCause() != null ? e.getCause() : e); 54 } 55 } 56 }
1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package com.alibaba.dubbo.rpc.cluster.support; 18 19 import com.alibaba.dubbo.common.logger.Logger; 20 import com.alibaba.dubbo.common.logger.LoggerFactory; 21 import com.alibaba.dubbo.rpc.Invocation; 22 import com.alibaba.dubbo.rpc.Invoker; 23 import com.alibaba.dubbo.rpc.Result; 24 import com.alibaba.dubbo.rpc.RpcException; 25 import com.alibaba.dubbo.rpc.RpcResult; 26 import com.alibaba.dubbo.rpc.cluster.Directory; 27 import com.alibaba.dubbo.rpc.cluster.LoadBalance; 28 29 import java.util.List; 30 31 /** 32 * When invoke fails, log the error message and ignore this error by returning an empty RpcResult. 33 * Usually used to write audit logs and other operations 34 * 35 * <a href="http://en.wikipedia.org/wiki/Fail-safe">Fail-safe</a> 36 * 37 */ 38 public class FailsafeClusterInvoker<T> extends AbstractClusterInvoker<T> { 39 private static final Logger logger = LoggerFactory.getLogger(FailsafeClusterInvoker.class); 40 41 public FailsafeClusterInvoker(Directory<T> directory) { 42 super(directory); 43 } 44 45 @Override 46 public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { 47 try { 48 checkInvokers(invokers, invocation); 49 Invoker<T> invoker = select(loadbalance, invocation, invokers, null); 50 return invoker.invoke(invocation); 51 } catch (Throwable e) { 52 logger.error("Failsafe ignore exception: " + e.getMessage(), e); 53 return new RpcResult(); // ignore 54 } 55 } 56 }
1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package com.alibaba.dubbo.rpc.cluster.support; 18 19 import com.alibaba.dubbo.common.logger.Logger; 20 import com.alibaba.dubbo.common.logger.LoggerFactory; 21 import com.alibaba.dubbo.common.utils.NamedThreadFactory; 22 import com.alibaba.dubbo.rpc.Invocation; 23 import com.alibaba.dubbo.rpc.Invoker; 24 import com.alibaba.dubbo.rpc.Result; 25 import com.alibaba.dubbo.rpc.RpcException; 26 import com.alibaba.dubbo.rpc.RpcResult; 27 import com.alibaba.dubbo.rpc.cluster.Directory; 28 import com.alibaba.dubbo.rpc.cluster.LoadBalance; 29 30 import java.util.HashMap; 31 import java.util.List; 32 import java.util.Map; 33 import java.util.concurrent.ConcurrentHashMap; 34 import java.util.concurrent.ConcurrentMap; 35 import java.util.concurrent.Executors; 36 import java.util.concurrent.ScheduledExecutorService; 37 import java.util.concurrent.ScheduledFuture; 38 import java.util.concurrent.TimeUnit; 39 40 /** 41 * When fails, record failure requests and schedule for retry on a regular interval. 42 * Especially useful for services of notification. 43 * 44 * <a href="http://en.wikipedia.org/wiki/Failback">Failback</a> 45 * 46 */ 47 public class FailbackClusterInvoker<T> extends AbstractClusterInvoker<T> { 48 49 private static final Logger logger = LoggerFactory.getLogger(FailbackClusterInvoker.class); 50 51 private static final long RETRY_FAILED_PERIOD = 5 * 1000; 52 53 private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2, new NamedThreadFactory("failback-cluster-timer", true)); 54 private final ConcurrentMap<Invocation, AbstractClusterInvoker<?>> failed = new ConcurrentHashMap<Invocation, AbstractClusterInvoker<?>>(); 55 private volatile ScheduledFuture<?> retryFuture; 56 57 public FailbackClusterInvoker(Directory<T> directory) { 58 super(directory); 59 } 60 61 private void addFailed(Invocation invocation, AbstractClusterInvoker<?> router) { 62 if (retryFuture == null) { 63 synchronized (this) { 64 if (retryFuture == null) { 65 retryFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() { 66 67 @Override 68 public void run() { 69 // collect retry statistics 70 try { 71 retryFailed(); 72 } catch (Throwable t) { // Defensive fault tolerance 73 logger.error("Unexpected error occur at collect statistic", t); 74 } 75 } 76 }, RETRY_FAILED_PERIOD, RETRY_FAILED_PERIOD, TimeUnit.MILLISECONDS); 77 } 78 } 79 } 80 failed.put(invocation, router); 81 } 82 83 void retryFailed() { 84 if (failed.size() == 0) { 85 return; 86 } 87 for (Map.Entry<Invocation, AbstractClusterInvoker<?>> entry : new HashMap<Invocation, AbstractClusterInvoker<?>>( 88 failed).entrySet()) { 89 Invocation invocation = entry.getKey(); 90 Invoker<?> invoker = entry.getValue(); 91 try { 92 invoker.invoke(invocation); 93 failed.remove(invocation); 94 } catch (Throwable e) { 95 logger.error("Failed retry to invoke method " + invocation.getMethodName() + ", waiting again.", e); 96 } 97 } 98 } 99 100 @Override 101 protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { 102 try { 103 checkInvokers(invokers, invocation); 104 Invoker<T> invoker = select(loadbalance, invocation, invokers, null); 105 return invoker.invoke(invocation); 106 } catch (Throwable e) { 107 logger.error("Failback to invoke method " + invocation.getMethodName() + ", wait for retry in background. Ignored exception: " 108 + e.getMessage() + ", ", e); 109 addFailed(invocation, this); 110 return new RpcResult(); // ignore 111 } 112 } 113 114 }
1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package com.alibaba.dubbo.rpc.cluster.support; 18 19 import com.alibaba.dubbo.common.Constants; 20 import com.alibaba.dubbo.common.utils.NamedThreadFactory; 21 import com.alibaba.dubbo.rpc.Invocation; 22 import com.alibaba.dubbo.rpc.Invoker; 23 import com.alibaba.dubbo.rpc.Result; 24 import com.alibaba.dubbo.rpc.RpcContext; 25 import com.alibaba.dubbo.rpc.RpcException; 26 import com.alibaba.dubbo.rpc.cluster.Directory; 27 import com.alibaba.dubbo.rpc.cluster.LoadBalance; 28 29 import java.util.ArrayList; 30 import java.util.List; 31 import java.util.concurrent.BlockingQueue; 32 import java.util.concurrent.ExecutorService; 33 import java.util.concurrent.Executors; 34 import java.util.concurrent.LinkedBlockingQueue; 35 import java.util.concurrent.TimeUnit; 36 import java.util.concurrent.atomic.AtomicInteger; 37 38 /** 39 * Invoke a specific number of invokers concurrently, usually used for demanding real-time operations, but need to waste more service resources. 40 * 41 * <a href="http://en.wikipedia.org/wiki/Fork_(topology)">Fork</a> 42 * 43 */ 44 public class ForkingClusterInvoker<T> extends AbstractClusterInvoker<T> { 45 46 private final ExecutorService executor = Executors.newCachedThreadPool(new NamedThreadFactory("forking-cluster-timer", true)); 47 48 public ForkingClusterInvoker(Directory<T> directory) { 49 super(directory); 50 } 51 52 @Override 53 @SuppressWarnings({"unchecked", "rawtypes"}) 54 public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { 55 checkInvokers(invokers, invocation); 56 final List<Invoker<T>> selected; 57 final int forks = getUrl().getParameter(Constants.FORKS_KEY, Constants.DEFAULT_FORKS); 58 final int timeout = getUrl().getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); 59 if (forks <= 0 || forks >= invokers.size()) { 60 selected = invokers; 61 } else { 62 selected = new ArrayList<Invoker<T>>(); 63 for (int i = 0; i < forks; i++) { 64 // TODO. Add some comment here, refer chinese version for more details. 65 Invoker<T> invoker = select(loadbalance, invocation, invokers, selected); 66 if (!selected.contains(invoker)) {//Avoid add the same invoker several times. 67 selected.add(invoker); 68 } 69 } 70 } 71 RpcContext.getContext().setInvokers((List) selected); 72 final AtomicInteger count = new AtomicInteger(); 73 final BlockingQueue<Object> ref = new LinkedBlockingQueue<Object>(); 74 for (final Invoker<T> invoker : selected) { 75 executor.execute(new Runnable() { 76 @Override 77 public void run() { 78 try { 79 Result result = invoker.invoke(invocation); 80 ref.offer(result); 81 } catch (Throwable e) { 82 int value = count.incrementAndGet(); 83 if (value >= selected.size()) { 84 ref.offer(e); 85 } 86 } 87 } 88 }); 89 } 90 try { 91 Object ret = ref.poll(timeout, TimeUnit.MILLISECONDS); 92 if (ret instanceof Throwable) { 93 Throwable e = (Throwable) ret; 94 throw new RpcException(e instanceof RpcException ? ((RpcException) e).getCode() : 0, "Failed to forking invoke provider " + selected + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e.getCause() != null ? e.getCause() : e); 95 } 96 return (Result) ret; 97 } catch (InterruptedException e) { 98 throw new RpcException("Failed to forking invoke provider " + selected + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e); 99 } 100 } 101 }
1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package com.alibaba.dubbo.rpc.cluster.support; 18 19 import com.alibaba.dubbo.common.logger.Logger; 20 import com.alibaba.dubbo.common.logger.LoggerFactory; 21 import com.alibaba.dubbo.rpc.Invocation; 22 import com.alibaba.dubbo.rpc.Invoker; 23 import com.alibaba.dubbo.rpc.Result; 24 import com.alibaba.dubbo.rpc.RpcContext; 25 import com.alibaba.dubbo.rpc.RpcException; 26 import com.alibaba.dubbo.rpc.cluster.Directory; 27 import com.alibaba.dubbo.rpc.cluster.LoadBalance; 28 29 import java.util.List; 30 31 /** 32 * BroadcastClusterInvoker 33 * 34 */ 35 public class BroadcastClusterInvoker<T> extends AbstractClusterInvoker<T> { 36 37 private static final Logger logger = LoggerFactory.getLogger(BroadcastClusterInvoker.class); 38 39 public BroadcastClusterInvoker(Directory<T> directory) { 40 super(directory); 41 } 42 43 @Override 44 @SuppressWarnings({"unchecked", "rawtypes"}) 45 public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { 46 checkInvokers(invokers, invocation); 47 RpcContext.getContext().setInvokers((List) invokers); 48 RpcException exception = null; 49 Result result = null; 50 for (Invoker<T> invoker : invokers) { 51 try { 52 result = invoker.invoke(invocation); 53 } catch (RpcException e) { 54 exception = e; 55 logger.warn(e.getMessage(), e); 56 } catch (Throwable e) { 57 exception = new RpcException(e.getMessage(), e); 58 logger.warn(e.getMessage(), e); 59 } 60 } 61 if (exception != null) { 62 throw exception; 63 } 64 return result; 65 } 66 67 }