Публичный аккаунт WeChat: маленький черный домовладелец
Поскольку дорога идет далеко, будущее будет лучше
Обучение безгранично, давайте работать вместе!
Когда мы сталкиваемся с проблемой всплеска трафика при высоком уровне параллелизма, часто упоминается, что降级
,熔断
и限流
Концепция чего-либо. Позвольте мне кратко объяснить определения этих трех понятий.
Связанные концепции
понижение рейтинга
Даунгрейд — это даунгрейд сервиса, когда нагрузка на наш сервер резко возрастает, чтобы обеспечить доступность основных функций, доступность некоторых функций выборочно снижается, либо функция сразу закрывается. Например, во время ажиотажа на покупку ранним утром в Double Eleven давление трафика очень велико.Чтобы обеспечить нормальную оплату заказа, функция модификации заказа закрывается около 1-2 часов ночи.
предохранитель
Понижение обычно относится к сбою нашей собственной системы и переходу на более раннюю версию. Слияние обычно означает, что связь с внешним интерфейсом прерывается, когда внешний интерфейс, который зависит от него, выходит из строя.
Например, функция в вашей службе A зависит от службы B. В настоящее время есть проблема со службой B, и возврат происходит очень медленно. Чем больше система, тем длиннее будут восходящие и нисходящие цепочки вызовов.Если служба в очень длинной цепочке вызовов по какой-то причине слишком долго отвечает или вообще не отвечает, это может привести к сбою всей распределенной системы. В этом случае из-за этой функции могут тормозиться все функции в сервисе А, а в тяжелых случаях это приведет кСервис ЛавинаФеномен.
В распределенных системах, чтобы обеспечить доступность и согласованность всего сервиса, многие системы будут использоватьмеханизм повторной попытки, эту меру можно использовать при некоторых сбоях из-за дрожания сети.
Однако в некоторых случаях нецелесообразно использоватьмеханизм повторной попытки, но еще больше снижает производительность системы. Например, ЦП нижестоящей системы переполнен из-за большого количества запросов или переполнен пул соединений с базой данных.В это время вышестоящая система вызывает нижестоящую систему для получения неведущей информации и будет продолжать повторять попытки. В этом случае повторная попытка очень затруднительна, чтобы вызвать коллапс нижестоящей системы.
В распределенной системе большинство лавин служб также вызвано непрерывными повторными попытками, которые могут быть автоматическими повторными попытками на уровне инфраструктуры, логикой повторных попыток на уровне кода или инициативой пользователя.
тогда мы можем использоватьРежим предохранителядля разрешения этого явления. Типичный предохранитель имеет три состояния:
1) закрыть
Автоматический выключатель по умолчанию выключен. Сам предохранитель имеет функцию подсчета.Всякий раз, когда возникает ошибка, счетчик будет накапливаться.Когда определенное количество раз, предохранитель будет включен, и в то же время будет включен таймер.Как только время истекло , он переключится на半开启
статус.
2) Включите
В открытом состоянии любой запрос будет напрямую отклонен, и будет выдано сообщение об исключении.
3) полуоткрытый
Автоматический выключатель разрешит некоторые запросы, если эти запросы пройдут успешно, то ошибки больше не будет, он будет переведен в выключенное состояние и счетчик будет сброшен. Если какой-либо из запросов завершится ошибкой, он вернется к开启
состояния и сбросьте таймер, давая системе перерыв.
Случайный разговор: Как объяснить своей девушке, что такое автоматический выключатель?
Ограничение
Это легко понять, то есть через оценку системы разрешается поступать только определенному количеству запросов, а остальные запросы отказываются выполнять. Например, в системе seckill для seckill 100 предметов я разрешаю ввод только первых 2000 запросов, а остальные напрямую перехватываются и отклоняются.
Теперь, когда мы объяснили эти три понятия, давайте начнем с объяснения.dubbo是如何降级的
.
Понижение сервиса Dubbo
Dubbo может временно защитить некритическую службу по ошибке с помощью функции перехода на более раннюю версию службы и определить политику возврата после перехода на более раннюю версию. Мы можем записать правила переопределения динамической конфигурации в реестр:
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"));
Его также можно определить через файл конфигурации.
<dubbo:reference id="iUser" interface="com.dubbosample.iface.IUser" timeout="1000" check="false" mock="return null">
Есть еще такие формы:
<dubbo:reference mock="true" .../>
<dubbo:reference mock="com.xxxx" .../>
<dubbo:reference mock="return null" .../>
<dubbo:reference mock="throw xxx" .../>
<dubbo:reference mock="force:return .." .../>
<dubbo:reference mock="force:throw ..." .../>
Среди них две наиболее важные формы:
1)mock='force:return+null'
Указывает, что вызовы методов, использующих службу, напрямую возвращают нулевые значения и не инициируют удаленные вызовы. Используется для защиты вызывающих абонентов, когда неважные услуги недоступны.
2) также можно изменить наmock=fail:return+null
Указывает, что вызов метода потребителя к службе завершился неудачно и затем возвращает значение null. Используется, чтобы допустить влияние на вызывающих абонентов, когда неважные услуги нестабильны.
специальный код
Те, кто читал исходный код, знают, что удаленный вызов Dubbo начинается с прокси-сервера Proxy, который сначала сохраняет параметры времени выполнения в массиве, а затем вызываетInvocationHandler
интерфейс для реализации классаinvoke
метод. Ниже приведен пример динамически сгенерированного прокси-класса.
public class proxy0 implements ClassGenerator.DC, EchoService, DemoService {
// 方法数组
public static Method[] methods;
private InvocationHandler handler;
public proxy0(InvocationHandler invocationHandler) {
this.handler = invocationHandler;
}
public proxy0() {
}
public String sayHello(String string) {
// 将参数存储到 Object 数组中
Object[] arrobject = new Object[]{string};
// 调用 InvocationHandler 实现类的 invoke 方法得到调用结果
Object object = this.handler.invoke(this, methods[0], arrobject);
// 返回调用结果
return (String)object;
}
public Object $echo(Object object) {
Object[] arrobject = new Object[]{object};
Object object2 = this.handler.invoke(this, methods[1], arrobject);
return object2;
}
}
InvokerInvocationHandler
серединаinvoker
переменная-членMockClusterInvoker
, который обрабатывает логику деградации службы.
public class InvokerInvocationHandler implements InvocationHandler {
private final Invoker<?> invoker;
public InvokerInvocationHandler(Invoker<?> handler) {
this.invoker = handler;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
// 拦截定义在 Object 类中的方法(未被子类重写),比如 wait/notify
if (method.getDeclaringClass() == Object.class) {
return method.invoke(invoker, args);
}
// 如果 toString、hashCode 和 equals 等方法被子类重写了,这里也直接调用
if ("toString".equals(methodName) && parameterTypes.length == 0) {
return invoker.toString();
}
if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
return invoker.hashCode();
}
if ("equals".equals(methodName) && parameterTypes.length == 1) {
return invoker.equals(args[0]);
}
// 将 method 和 args 封装到 RpcInvocation 中,并执行后续的调用
return invoker.invoke(new RpcInvocation(method, args)).recreate();
}
}
существуетMockClusterInvoker
в отno mock(正常情况)
,force:direct mock(屏蔽)
,fail-mock(容错)
Мы также можем видеть, что в трех случаях нормальный случай - это вызов напрямую, а отказоустойчивый случай - возврат установленного значения после сбоя вызова. И экранирование очень сильное. Если вызов не вызывается напрямую, он напрямую вернет ранее установленное значение.
Как видно из комментариев ниже, при отсутствии даунгрейда выполнениеthis.invoker.invoke(invocation)
метод удаленной передачи, класс по умолчаниюFailoverClusterInvoker
, он будет выполнять логику кластерного модуля, в основном вызываяDirectory#list
Метод получает список адресов всех поставщиков услуг, а затем объединяет несколько поставщиков услуг в один.Invoker
, и вызовите метод Router для маршрутизации, чтобы отфильтровать Invokers, которые не соответствуют правилам маршрутизации. Когда FailoverClusterInvoker получает список Invoker, возвращенный Directory, он выбирает Invoker из списка Invoker через LoadBalance. Наконец, FailoverClusterInvoker передаст параметры методу вызова экземпляра Invoker, выбранного LoadBalance для выполнения реального удаленного вызова.
public class MockClusterInvoker<T> implements Invoker<T> {
private final Invoker<T> invoker;
public Result invoke(Invocation invocation) throws RpcException {
Result result = null;
// 获取 mock 配置值
String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim();
if (value.length() == 0 || value.equalsIgnoreCase("false")) {
// 无 mock 逻辑,直接调用其他 Invoker 对象的 invoke 方法,
// 比如 FailoverClusterInvoker
result = this.invoker.invoke(invocation);
} else if (value.startsWith("force")) {
// force:xxx 直接执行 mock 逻辑,不发起远程调用
result = doMockInvoke(invocation, null);
} else {
// fail:xxx 表示消费方对调用服务失败后,再执行 mock 逻辑,不抛出异常
try {
// 调用其他 Invoker 对象的 invoke 方法
result = this.invoker.invoke(invocation);
} catch (RpcException e) {
if (e.isBiz()) {
throw e;
} else {
// 调用失败,执行 mock 逻辑
result = doMockInvoke(invocation, e);
}
}
}
return result;
}
// 省略其他方法
}
Справочная статья:
понижение уровня обслуживания
Анализ исходного кода Dubbo — сервисная деградация дизайна логического уровня
удаленный вызов
Интервьюер: Поговорите о даунгрейдах, автоматических выключателях и ограничении тока.