В этой статье рассказывается, как использовать настраиваемую полезную нагрузку dubbo для реализации простых оттенков серого (широта пользователя, некоторые пользователи получают доступ к одной службе, а остальные — к остальным службам).
На самом деле, до этого я мало что знал о dubbo. Я просто немного использовал его и запустил несколько демонстраций. Но, зная, что в следующий раз я могу использовать dubbo для разработки, я быстро пополнил соответствующие знания и посмотрел. официальном сайте, я также купил книгу "Углубленное понимание Apache Dubbo Combat", я прочитал больше половины, и это очень хорошо.
1. Внедрение балансировки нагрузки dubbo
Поскольку официальный сайт очень подробный, здесь я расскажу об этом лишь вкратце. Балансировка нагрузки Dubbo включает следующие четыре типа:
- RandomLoadBalance: стратегия загрузки по умолчанию, случайная загрузка.
- ConsistentHashLoadBalance: постоянная хэш-нагрузка.
- LeastActiveLoadBalance: наименьшая активная нагрузка.
- RoundRobinLoadBalance: циклическая загрузка.
Вы можете посмотреть официальный:Хироши Ватанабэ.apache.org/this-capable/docs/…
Все эти четыре класса наследуют абстрактный класс AbstractLoadBalance.Для анализа исходного кода вы можете просмотреть официальный:Хироши Ватанабэ.apache.org/this-capable/docs/…
2. springboot-dubbo реализует пользовательский метод загрузки
На самом деле для springboot-dubbo очень просто использовать пользовательскую загрузку, которую можно условно разделить на следующие шаги:
- 1. Создайте собственный класс нагрузки, унаследуйте от класса AbstractLoadBalance и переопределите метод doSelect, в котором определяются правила алгоритма.
- 2. Добавьте точку расширения загрузки dubbo, создайте каталог META-INFO/dubbo в каталоге src/main/resources, создайте в каталоге файл org.apache.dubbo.rpc.cluster.LoadBalance и настройте соответствующий алгоритм загрузки. класса следующим образом:
gray=com.dalaoyang.balance.GrayLoadBalance
- 3. Используется в файле конфигурации следующим образом:
dubbo.provider.loadbalance=gray
3. Моделирование схемы оттенков серого и конкретная реализация
3.1 Сцена в оттенках серого
Теперь смоделируйте такую схему, например, есть 4 поставщика услуг, порты 9001, 9002, 9003, 9004, а служба порта 9002 настроена как служба в оттенках серого, а идентификатор пользователя запроса пользовательского интерфейса testUser равен 1. -10 При принудительной пересылке провайдеру в полутоновом состоянии остальные по-прежнему запрашивают обычную услугу, как показано на рисунке.
3.2 Реализация кода
Затем используйте код, чтобы просто реализовать описанный выше сценарий.
3.2.1 Поставщики услуг
Сначала посмотрите на файл pom, все зависимости от springboot-dubbo, а именно:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.dalaoyang</groupId>
<artifactId>springboot_dubbo_provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot_dubbo_provider</name>
<description>springboot_dubbo_provider</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Aapche Dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.1</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.2</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.8.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
<version>3.4.10</version>
<type>pom</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Затем предоставьте интерфейс для использования потребителями услуг следующим образом:
package com.dalaoyang.api;
public interface UserService {
String testUser(Long userId, String version);
}
Класс реализации, интерфейс возвращает соответствующий порт, порт dubbo, следующим образом:
package com.dalaoyang.api.impl;
import com.dalaoyang.api.UserService;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Value;
@Service
public class UserServiceImpl implements UserService {
@Value("${server.port}")
private String port;
@Value("${dubbo.protocol.port}")
private String dubboPort;
@Override
public String testUser(Long userId, String version) {
return "调用成功,端口是:" + port +
"。版本号是:" + version +
",用户id:" + userId +
",dubbo端口:" + dubboPort;
}
}
Создайте GrayLoadBalance, наследующий класс AbstractLoadBalance, который содержит следующую конфигурацию:
- Неявный параметр dubbo, используемый идентификатором пользователя текущего запроса (можно использовать и другие методы).
- Список пользователей в оттенках серого настраивается в конфигурации потребителя.
- Статус свойства настраивается в конфигурации поставщика услуг, чтобы различать, является ли это производственной службой или серой службой.
- Если подходящего объекта нет, используйте для распределения стратегию случайной загрузки.
После прочтения приведенного выше введения гораздо легче взглянуть на код.Примерно можно извлечь запрошенный идентификатор пользователя и набор идентификаторов пользователя в градациях серого, чтобы определить, является ли он пользователем в градациях серого.Если это так, выберите службу градаций серого, как показано ниже:
package com.dalaoyang.balance;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.cluster.loadbalance.AbstractLoadBalance;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
@Component
public class GrayLoadBalance extends AbstractLoadBalance {
public static final String NAME = "gray";
public GrayLoadBalance() {
}
@Override
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
List<Invoker<T>> list = new ArrayList<>();
for (Invoker invoker : invokers) {
list.add(invoker);
}
Map<String, String> map = invocation.getAttachments();
String userId = map.get("userId");
Iterator<Invoker<T>> iterator = list.iterator();
String grayUserIds = url.getParameter("grayUserids", "");
String[] arrs = grayUserIds.split(",");
while (iterator.hasNext()) {
Invoker<T> invoker = iterator.next();
String providerStatus = invoker.getUrl().getParameter("status", "prod");
if (Objects.equals(providerStatus, NAME)) {
if (Arrays.asList(arrs).contains(userId)) {
return invoker;
} else {
iterator.remove();
}
}
}
return this.randomSelect(list, url, invocation);
}
/**
* 重写了一遍随机负载策略
*
* @param invokers
* @param url
* @param invocation
* @param <T>
* @return
*/
private <T> Invoker<T> randomSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
int length = invokers.size();
boolean sameWeight = true;
int[] weights = new int[length];
int firstWeight = this.getWeight((Invoker) invokers.get(0), invocation);
weights[0] = firstWeight;
int totalWeight = firstWeight;
int offset;
int i;
for (offset = 1; offset < length; ++offset) {
i = this.getWeight((Invoker) invokers.get(offset), invocation);
weights[offset] = i;
totalWeight += i;
if (sameWeight && i != firstWeight) {
sameWeight = false;
}
}
if (totalWeight > 0 && !sameWeight) {
offset = ThreadLocalRandom.current().nextInt(totalWeight);
for (i = 0; i < length; ++i) {
offset -= weights[i];
if (offset < 0) {
return (Invoker) invokers.get(i);
}
}
}
return (Invoker) invokers.get(ThreadLocalRandom.current().nextInt(length));
}
}
Затем добавьте новую точку расширения org.apache.dubbo.rpc.cluster.LoadBalance в src/main/resources/META-INF/dubbo следующим образом:
gray=com.dalaoyang.balance.GrayLoadBalance
Здесь используется несколько конфигурационных файлов для запуска нескольких сервис-провайдеров.Содержимое основного конфигурационного файла application.properties выглядит следующим образом:
spring.profiles.active=test3
dubbo.provider.loadbalance=gray
Содержимое application-test1.properties следующее:
##端口号
server.port=9001
## Dubbo配置
dubbo.application.name=dubbo_provider
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=9011
dubbo.scan.base-packages=com.dalaoyang
dubbo.provider.version=2.0.0
Содержимое application-test2.properties выглядит следующим образом: здесь свойство dubbo.provider.parameters.status=gray настроено для различения сервисов в градациях серого:
##端口号
server.port=9002
## Dubbo配置
dubbo.application.name=dubbo_provider
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=9012
dubbo.scan.base-packages=com.dalaoyang
dubbo.provider.version=2.0.0
dubbo.provider.parameters.status=gray
Содержимое application-test3.properties следующее:
##端口号
server.port=9003
## Dubbo配置
dubbo.application.name=dubbo_provider
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=9013
dubbo.scan.base-packages=com.dalaoyang
dubbo.provider.version=2.0.0
Содержимое application-test4.properties следующее:
##端口号
server.port=9004
## Dubbo配置
dubbo.application.name=dubbo_provider
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=9014
dubbo.scan.base-packages=com.dalaoyang
dubbo.provider.version=2.0.0
На этом этапе создается поставщик услуг.
3.2.2 Потребители услуг
Потребитель услуги намного проще.В дополнение к соответствующему пакету dubbo, файл pom вводит пакет поставщика услуг следующим образом:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.dalaoyang</groupId>
<artifactId>springboot_dubbo_consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot_dubbo_consumer</name>
<description>springboot_dubbo_consumer</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Aapche Dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.1</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.2</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.dalaoyang</groupId>
<artifactId>springboot_dubbo_provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.8.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
<version>3.4.10</version>
<type>pom</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Требуемый выше список идентификаторов пользователей в оттенках серого настраивается в файле конфигурации следующим образом:
## 端口号
server.port=8881
##Dubbo配置
dubbo.application.name=dubbo_consumer
dubbo.registry.address=zookeeper://localhost:2181
dubbo.scan.base-packages=com.dalaoyang.api
dubbo.consumer.version=2.0.0
dubbo.consumer.parameters.grayUserids=1,2,3,4,5,6,7,8,9,10
dubbo.provider.loadbalance=gray
dubbo.protocol.port=10000
Создайте TestController, напишите простой тестовый класс, вызовите сервис dubbo, содержимое будет следующим:
package com.dalaoyang.controller;
import com.dalaoyang.api.UserService;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.rpc.RpcContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Objects;
@RestController
public class TestController {
@Reference
private UserService userService;
//灰度用户 http://localhost:8881/testUser?userId=3333&version=2.0.0
//正常用户 http://localhost:8881/testUser?userId=10&version=2.0.0
@GetMapping("/testUser")
public String testUser(Long userId, String version) {
RpcContext.getContext().setAttachment("userId", Objects.nonNull(userId) ? userId.toString() : "");
return userService.testUser(userId, version);
}
}
Здесь также завершается потребитель услуги.
4. Тест
4.1 Запустить проект
- 1. Запустите зоопарк
- 2. Чтобы запустить поставщика услуг, вы можете использовать идею запуска нескольких служб, или вы можете упаковать его и сформулировать различные файлы конфигурации для запуска любым способом.
- 3. После запуска поставщика услуг запустите потребителя услуг.
4.2 Запрос страницы
Если служба в состоянии оттенков серого запущена, доступhttp://localhost:8881/testUser?userId=10&version=2.0.0, как показано на рисунке.
Если служба в состоянии оттенков серого не запущена или идентификатор пользователя не находится в диапазоне от 1 до 10, она будет отображаться, как показано на следующем рисунке.
[картина]
5. Исходный код
Весь соответствующий исходный код этой статьи был загружен в облако кода, адресgit ee.com/Большой Брат Ян/Да…