Эта статья написанаyanglbmeНачалось вДокументы технического сообщества GitHub, текущие звезды превысили 30k.
адрес проекта:GitHub.com/ohohgenerate/advpress…
опубликовано ранее«Несмотря на то, что Hystrix больше не поддерживается, его все равно стоит изучить!», и заинтересованные копатели также могут сначала взглянуть. В этой статье в основном рассказывается, как использовать Hystrix для достиженияИзоляция ресурсов, давайте посмотрим~
Прежде чем перейти к теме, давайте взглянем на системную архитектуру страницы сведений о продукте на веб-сайте электронной коммерции.
Системная архитектура страницы сведений о продукте веб-сайта электронной коммерции
Архитектура системы страницы сведений о продукте для небольших веб-сайтов электронной коммерции
Отображение страницы небольших веб-сайтов электронной коммерции использует идею полной статической страницы. Вся информация о продукте хранится в базе данных, а страница делается статической в системе, которая заполняет данные в статическом шаблоне для формирования статической страницы и отправляет ее на сервер Nginx. Когда пользователь просматривает страницу веб-сайта, он берет статическую html-страницу и возвращает ее напрямую без какой-либо обработки бизнес-логики.
Ниже приведена простая демонстрация шаблона страницы.
<html>
<body>
商品名称:#{productName}<br>
商品价格:#{productPrice}<br>
商品描述:#{productDesc}
</body>
</html>
Сюда,выгодаДело в том, что каждый раз, когда пользователь просматривает страницу, ему не нужно выполнять какую-либо логику взаимодействия с базой данных, а также ему не нужно выполнять какой-либо код, просто возвращать html-страницу напрямую, а скорость и производительность очень высоки.
Для небольших веб-сайтов есть несколько страниц, очень практичных и очень простых.Вы можете использовать скорость, freemarker, тимелеаф и т. д. на Java, а затем сделать систему управления контентом страницы cms.Когда шаблон изменен, нажмите кнопку или система автоматически перерисовывает всю сумму.
вредОднако это применимо только к некоторым небольшим веб-сайтам, например, масштаб страниц колеблется от десятков до десятков тысяч. Для некоторых крупных веб-сайтов электронной коммерции с сотнями миллионов страниц вы сказали, что каждый раз, когда вы изменяете шаблон страницы, вам нужно сделать так много страниц статическими.Надежно ли это? Каждый раз требуется несколько дней на рендеринг, и весь ваш сайт станет бесполезным.
Системная архитектура страницы сведений о продукте крупных веб-сайтов электронной коммерции
В системном дизайне страницы сведений о продукте крупного веб-сайта электронной коммерции при изменении данных о продукте сообщение об изменении будет помещено в очередь сообщений MQ.кэш-сервисПри использовании этого сообщения из очереди сообщений он определяет, что данные изменились, затем получает измененные данные, вызывая интерфейс службы данных, а затем отправляет интегрированные данные в Redis. Данные, кэшированные локально Nginx, имеют определенное ограничение по времени, например, 10 минут. Когда срок действия данных истечет, он получит последние кэшированные данные из Redis и кэширует их локально.
Когда пользователь просматривает веб-страницу, локальные данные Nginx динамически отображаются в локальном HTML-шаблоне и возвращаются пользователю.
Хотя это не так быстро, как возврат html-страницы напрямую, поскольку данные кэшируются локально, это также очень быстро Фактически, стоимость - это производительность динамического рендеринга html-страницы. Если шаблон html изменен, нет необходимости повторно статизировать все страницы и отправлять запрос. потом ответил.
В рамках этой архитектуры нам нужноОбеспечение высокой доступности системы.
Если объем доступа к системе высок, локальный кеш Nginx истекает, а кеш в redis также очищается алгоритмом LRU, будет большой объем трафика, и товарный сервис будет вызываться из сервиса кеша. Однако, если в это время происходит сбой интерфейса товарной службы, вызов задерживается, и все потоки кэш-сервиса исчерпываются вызывающим интерфейсом товарной службы. Когда каждый поток вызывает интерфейс товарной службы, он застревает на В это время там будет зависать большое количество запросов. В это время у службы кеша не хватает потоков для вызова интерфейсов некоторых других служб, поэтому все большое количество страниц с описанием товара не может отображаться нормально.
На самом деле это явление, при котором сбой службы стандартного интерфейса приводит к истощению ресурсов службы кэша.
Изоляция ресурсов на основе технологии пула потоков Hystrix
Как упоминалось выше, если кеш недействителен из Nginx, Nginx будет напрямую вызывать службу продукта через службу кеша, чтобы получить последние данные о продукте (мы обсудим на основе проекта электронной коммерции), может быть задержка в вызове и ситуация с исчерпанием ресурсов службы кеша. Здесь давайте поговорим о том, как добиться изоляции ресурсов с помощью технологии пула потоков Hystrix.
Изоляция ресурсов, то есть если вы хотите изолировать все вызовы зависимой службы в том же пуле ресурсов и не будете использовать другие ресурсы, это называется изоляцией ресурсов. Даже для этой зависимой службы, такой как товарная служба, количество одновременных вызовов достигло 1000, но в пуле потоков товарной службы выделено только 10 потоков, и только эти 10 потоков используются для выполнения максимум. Все ресурсы потоков внутри Tomcat не будут исчерпаны из-за задержки вызова обычных служб.
Для изоляции ресурсов Hystrix фактически предоставляет абстракцию под названием Command. Это также самая основная технология изоляции ресурсов Hystrix.
Используйте HystrixCommand для получения одного фрагмента данных
Мы определяем ключ, инкапсулируя операцию вызова товарных служб в HystrixCommand, например:GetProductInfoCommandGroup
, здесь мы можем просто думать, что это пул потоков.Каждый раз, когда вызывается товарная служба, будут использоваться только ресурсы в пуле потоков, а другие ресурсы потока не будут использоваться.
public class GetProductInfoCommand extends HystrixCommand<ProductInfo> {
private Long productId;
public GetProductInfoCommand(Long productId) {
super(HystrixCommandGroupKey.Factory.asKey("GetProductInfoCommandGroup"));
this.productId = productId;
}
@Override
protected ProductInfo run() {
String url = "http://localhost:8081/getProductInfo?productId=" + productId;
// 调用商品服务接口
String response = HttpClientUtils.sendGetRequest(url);
return JSONObject.parseObject(response, ProductInfo.class);
}
}
В интерфейсе службы кеша мы создаем команду на основе productId и выполняем ее для получения данных о продукте.
@RequestMapping("/getProductInfo")
@ResponseBody
public String getProductInfo(Long productId) {
HystrixCommand<ProductInfo> getProductInfoCommand = new GetProductInfoCommand(productId);
// 通过command执行,获取最新商品数据
ProductInfo productInfo = getProductInfoCommand.execute();
System.out.println(productInfo);
return "success";
}
Метод execute() выполняется выше, что на самом деле является синхронным. Вы также можете вызвать метод queue() для команды. Он просто помещает команду в очередь ожидания в пуле потоков, немедленно возвращается и получает объект Future. Вы можете продолжить делать другие вещи позже, а затем вызвать get on Будущее через определенный период времени.() метод для получения данных. Это асинхронно.
Используйте HystrixObservableCommand для пакетного получения данных.
Пока данные о продукте получены, все они привязаны к одному и тому же пулу потоков.Мы выполняем его через поток HystrixObservableCommand, и в этом потоке productInfo нескольких productId извлекается пакетами.
public class GetProductInfosCommand extends HystrixObservableCommand<ProductInfo> {
private String[] productIds;
public GetProductInfosCommand(String[] productIds) {
// 还是绑定在同一个线程池
super(HystrixCommandGroupKey.Factory.asKey("GetProductInfoGroup"));
this.productIds = productIds;
}
@Override
protected Observable<ProductInfo> construct() {
return Observable.unsafeCreate((Observable.OnSubscribe<ProductInfo>) subscriber -> {
for (String productId : productIds) {
// 批量获取商品数据
String url = "http://localhost:8081/getProductInfo?productId=" + productId;
String response = HttpClientUtils.sendGetRequest(url);
ProductInfo productInfo = JSONObject.parseObject(response, ProductInfo.class);
subscriber.onNext(productInfo);
}
subscriber.onCompleted();
}).subscribeOn(Schedulers.io());
}
}
В интерфейсе службы кеша по переданному списку id, например,,
Разделенная строка идентификатора с помощью приведенной выше команды HystrixObservableCommand выполняет некоторые методы API Hystrix для получения всех данных о продукте.
public String getProductInfos(String productIds) {
String[] productIdArray = productIds.split(",");
HystrixObservableCommand<ProductInfo> getProductInfosCommand = new GetProductInfosCommand(productIdArray);
Observable<ProductInfo> observable = getProductInfosCommand.observe();
observable.subscribe(new Observer<ProductInfo>() {
@Override
public void onCompleted() {
System.out.println("获取完了所有的商品数据");
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
/**
* 获取完一条数据,就回调一次这个方法
* @param productInfo
*/
@Override
public void onNext(ProductInfo productInfo) {
System.out.println(productInfo);
}
});
return "success";
}
Давайте вернемся назад и посмотрим, как технология пула потоков Hystrix обеспечивает изоляцию ресурсов.
Начиная с Nginx, кеш недействителен, затем Nginx вызывает товарный сервис через кеш-сервис. Размер потока службы кэширования по умолчанию равен 10, и не более 10 потоков могут вызывать интерфейс стандартной службы. Даже если интерфейс стандартной службы выйдет из строя, не более 10 потоков будут зависать и умирать на пути к вызову интерфейса стандартной службы, а другие потоки в Tomcat службы кэширования все еще могут использоваться для вызова других служб и выполнения других действий.
Изоляция ресурсов на основе семафорного механизма Hystrix
Основной функцией в Hystrix на самом деле является так называемаяИзоляция ресурсов, основная проблема, которую необходимо решить, — это изоляция вызовов нескольких зависимых служб в их собственные пулы ресурсов. Избегайте вызова зависимой службы, так как задержка или сбой вызова интерфейса зависимой службы приводит к тому, что все ресурсы потока службы тратятся на вызов интерфейса этой службы. Когда ресурсы потока службы полностью исчерпаны, это может привести к сбою службы или даже к тому, что этот сбой будет продолжать распространяться.
Hystrix реализует изоляцию ресурсов, в основном, в двух технологиях:
- Пул потоков
- сигнал
По умолчанию Hystrix использует режим пула потоков.
Технология пула потоков уже упоминалась ранее, в этом разделе будет рассказано о семафорном механизме для достижения изоляции ресурсов, а также о различиях и конкретных сценариях применения этих двух технологий.
Семафорный механизм
Изоляция ресурсов семафора действует только как переключатель.Например, размер семафора службы A равен 10, что означает, что он позволяет только 10 потокам tomcat обращаться к службе A одновременно, а другие запросы будут отклонены, поэтому как достичь роли изоляции ресурсов и защиты от ограничения тока.
Разница между пулом потоков и семафором
Технология изоляции пула потоков не предназначена для управления потоками веб-контейнеров, таких как tomcat. В более строгом смысле, технология изоляции пула потоков Hystrix контролирует выполнение потоков tomcat. После того, как пул потоков Hystrix заполнен, он гарантирует, что поток tomcat не будет зависать из-за задержки или сбоя вызова зависимого от службы интерфейса, а другие потоки tomcat не будут зависать и могут быстро вернуться, и затем поддержите другие вещи.
Технология изоляции пула потоков использует собственные потоки Hystrix для выполнения вызовов, в то время как технология изоляции семафоров напрямую позволяет потокам tomcat вызывать зависимые службы. Изоляция семафора — это всего лишь контрольная точка: сколько потоков tomcat разрешено проходить через семафор и затем выполняться.
Применимая сцена:
- технология пула потоков, подходит для большинства сценариев, например, мы звоним и получаем доступ к сервис-зависимым сетевым запросам, и нам нужно контролировать время ожидания вызова (перехватывать исключение времени ожидания).
- Семафорная технология, уместно сказать, что ваш доступ - это не доступ к внешним зависимостям, а доступ к какой-то более сложной бизнес-логике внутри, а код внутри системы фактически не предполагает никаких сетевых запросов, поэтому просто сделайте обычное текущее ограничение семафоров Это нормально , потому что нет необходимости фиксировать такие проблемы, как тайм-аут.
Простая демонстрация семафора
В контексте бизнеса, какие сценарии больше подходят для семафоров?
Например, в общем случае служба кэширования может хранить некоторые данные, которые очень малы и к которым часто обращаются, в своей собственной чистой памяти.
Возьмите каштан. Как правило, после получения данных о продукте мы должны узнать, к какому географическому положению, провинции, городу, продавцу и т. д. принадлежит продукт, который может находиться в нашей собственной чистой памяти, например, на карте. Для такой логики, которая напрямую обращается к локальной памяти, больше подходит использование семафора для простой изоляции.
Преимущество заключается в том, что вам не нужно самостоятельно управлять пулом потоков, вам не нужно заботиться о тайм-ауте и не нужно выполнять переключение контекста потоков. Если семафор изолирован, производительность будет относительно выше.
Если это локальный кеш, мы можем получить cityName через cityId.
public class LocationCache {
private static Map<Long, String> cityMap = new HashMap<>();
static {
cityMap.put(1L, "北京");
}
/**
* 通过cityId 获取 cityName
*
* @param cityId 城市id
* @return 城市名
*/
public static String getCityName(Long cityId) {
return cityMap.get(cityId);
}
}
Напишите GetCityNameCommand с установленной политикойсигнал. Локальный кеш получается в методе run(). Наша цель — изолировать ресурсы для кода, который получает локальный кеш.
public class GetCityNameCommand extends HystrixCommand<String> {
private Long cityId;
public GetCityNameCommand(Long cityId) {
// 设置信号量隔离策略
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GetCityNameGroup"))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE)));
this.cityId = cityId;
}
@Override
protected String run() {
// 需要进行信号量隔离的代码
return LocationCache.getCityName(cityId);
}
}
На уровне интерфейса путем создания GetCityNameCommand, передачи cityId и выполнения метода execute() код для получения локального кэша cityName будет выполнять изоляцию ресурсов семафора.
@RequestMapping("/getProductInfo")
@ResponseBody
public String getProductInfo(Long productId) {
HystrixCommand<ProductInfo> getProductInfoCommand = new GetProductInfoCommand(productId);
// 通过command执行,获取最新商品数据
ProductInfo productInfo = getProductInfoCommand.execute();
Long cityId = productInfo.getCityId();
GetCityNameCommand getCityNameCommand = new GetCityNameCommand(cityId);
// 获取本地内存(cityName)的代码会被信号量进行资源隔离
String cityName = getCityNameCommand.execute();
productInfo.setCityName(cityName);
System.out.println(productInfo);
return "success";
}
Полный текст готов.
Спасибо всем следующим друзьямДокументы технического сообщества GitHubвнесенный вклад.
Добро пожаловать в мою общедоступную учетную запись WeChat «Сообщество открытого исходного кода Doocs». Оригинальные технические статьи будут опубликованы как можно скорее.