Введение Koalas-RPC — это личный проект, который предоставляет возможность для общения и обучения. Если у вас есть какие-либо замечания или предложения, пожалуйста, свяжитесь со мной. Я также приветствую обратную связь.
На рынке существует множество популярных RPC-фреймворков, таких как grpc, motan и dubbo. Однако по мере добавления всё большего количества элементов, сложная архитектура проектирования и другие факторы делают эти фреймворки похожими на spring. Хотя они и называются лёгкими, на самом деле они вызывают у нас затруднения. Большое количество конфигураций, сложный API-дизайн... На самом деле мы вообще не используем эти вещи! Я также считаю себя ветераном многих интернет-компаний. Я видел много внутренних RPC-фреймворков. Некоторые из них имеют отличный дизайн, и я очень их ценю. Однажды я внезапно подумал, почему бы не объединить эти дизайнерские прототипы и создать свой собственный лёгкий RPC-фреймворк? Из-за работы у меня никогда не было времени на это. Во время отпуска я решил попробовать. Было трудно решить множество мелких проблем, таких как обработка большого количества wait-time в TCP, как сделать Thrift и Netty совместимыми и т. д. Надеюсь, исходный код поможет людям лучше понять концепцию RPC-фреймворка. Чем больше я пишу, тем больше у меня возникает вопросов. Если у вас есть вопросы, пожалуйста, не стесняйтесь задавать их мне.
Название «Koalas» происходит от английского слова «koala», что означает «коала». Это символизирует то, что Koalas-RPC предоставляет надёжную среду использования RPC для тех, кто не любит создавать свои собственные колёса.
Koalas-RPC стремится быть простым и лёгким. Требуется только сервер zookeeper для обнаружения служб (в будущих версиях может потребоваться источник данных для управления службами). Для получения инструкций по установке zookeeper обратитесь к соответствующим ресурсам. Если вам нужна функция просмотра данных cat, вам потребуется установить cat-сервис. Установка cat очень проста: просто поместите war-файл в tomcat и настройте несколько параметров. Конечно, вы можете не использовать cat и использовать Koalas-RPC как отдельный RPC-фреймворк.
Maven-зависимости:
<dependency>
<groupId>koalas.rpc</groupId>
<artifactId>com.Koalas.rpc</artifactId>
<version>Koalas-1.0-SNAPSHOT</version>
</dependency>
Сначала необходимо написать собственный файл IDL для Thrift. Здесь следует отметить, что при написании файла IDL для Thrift могут возникнуть ошибки, если вы не знакомы с этим процессом. Рекомендуется обратиться к статьям и руководствам по написанию файлов IDL. Ниже приведён пример файла IDL для тестирования.
namespace java thrift.service
include 'TestCreateAccountRequest.thrift'
include 'TestCreateAccountRespone.thrift'
service TestCreateAccountService {
TestCreateAccountRespone.TestCreateAccountRespone getRPC(1:TestCreateAccountRequest.TestCreateAccountRequest TestCreateAccountRequest);
TestCreateAccountRespone.TestCreateAccountRespone koaloasTest1(1:TestCreateAccountRequest.TestCreateAccountRequest TestCreateAccountRequest);
TestCreateAccountRespone.TestCreateAccountRespone koaloasTest2(1:TestCreateAccountRequest.TestCreateAccountRequest TestCreateAccountRequest);
TestCreateAccountRespone.TestCreateAccountRespone koaloasTest3(1:TestCreateAccountRequest.TestCreateAccountRequest TestCreateAccountRequest);
TestCreateAccountRespone.TestCreateAccountRespone
``` **1. Клиентский вызов**
В данном фрагменте кода описывается конфигурация клиента для вызова удалённого RPC-сервиса. В коде используются пространства имён XML-схем, которые определяют структуру и типы данных для конфигурации.
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:koalas="http://www.koalas.com/schema/ch"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.koalas.com/schema/ch
http://www.koalas.com/schema/ch.xsd">
<koalas:client id="TestCreateAccountService2"
serviceInterface="thrift.service.TestCreateAccountService"
zkPath="127.0.0.1:2181"
async="true"/>
</beans>
Здесь определяется клиент с идентификатором TestCreateAccountService2, который будет использовать интерфейс сервиса thrift.service.TestCreateAccountService. Также указывается путь к ZooKeeper (zkPath) и устанавливается значение async в true, что означает асинхронный режим работы.
**2. Асинхронный вызов в Java**
package thrift.service;
import client.async.KoalasAsyncCallBack;
import org.apache.thrift.TException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import thrift.domain.TestCreateAccountRequest;
import thrift.domain.TestCreateAccountRespone;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@Service("testService")
public class TestService2 {
@Autowired
TestCreateAccountService.AsyncIface TestCreateAccountService;
public void getRemoteRpc() throws TException{
KoalasAsyncCallBack<TestCreateAccountRespone, TestCreateAccountService.AsyncClient.getRPC_call>
koalasAsyncCallBack = new KoalasAsyncCallBack<> ();
TestCreateAccountRequest request= new TestCreateAccountRequest ( );
request.setAccountType ( 1 );
request.setPartnerId ( 1 );
request.setPartnerType ( 1 );
request.setPartnerName ( "你好啊" );
request.setPoiFlag ( 1 );
TestCreateAccountService.getRPC ( request ,koalasAsyncCallBack);
Future<TestCreateAccountRespone> future= koalasAsyncCallBack.getFuture ();
try {
//to get other things
System.out.println (future.get ());
} catch (InterruptedException e) {
e.printStackTrace ();
} catch (ExecutionException e) {
e.printStackTrace ();
}
}
}
Этот фрагмент кода описывает класс TestService2, который выполняет асинхронный удалённый вызов RPC-метода getRPC. Метод getRemoteRpc создаёт экземпляр KoalasAsyncCallBack и передаёт ему параметры для вызова. Затем вызывается метод getRPC, который возвращает Future. После этого можно выполнять другие действия, пока не будет получен результат вызова через future.get().
**3. Реализация сервера**
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:koalas="http://www.koalas.com/schema/ch"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.koalas.com/schema/ch
http://www.koalas.com/schema/ch.xsd">
<koalas:server id="TestCreateAccountService"
serviceInterface="thrift.service.TestCreateAccountService"
serviceImpl="TestCreateAccountServiceImpl"
port="8001"
zkpath="127.0.0.1:2181"/>
</beans>
Данный фрагмент описывает конфигурацию сервера для предоставления RPC-сервиса TestCreateAccountService. Указываются интерфейс сервиса, реализация сервиса и параметры порта и адреса ZooKeeper.
@Service public class TestCreateAccountServiceImpl implements TestCreateAccountService.Iface { @Override public TestCreateAccountRespone getRPC(TestCreateAccountRequest TestCreateAccountRequest) throws TException { TestCreateAccountRespone TestCreateAccountRespone = new TestCreateAccountRespone (); TestCreateAccountRespone.setCode ( 1 ); TestCreateAccountRespone.setMessage ( "你好" ); if(new Random ( ).nextInt ( 5 )>100){ throw new RuntimeException ( "测试错误" ); } System.out.println ( "getRPC start ...." + TestCreateAccountRequest + "------" + atomicInteger.incrementAndGet () );
return TestCreateAccountRespone;
}
}
Этот код описывает реализацию интерфейса TestCreateAccountService для сервера. Метод getRPC обрабатывает запрос и возвращает ответ. ```
private AtomicInteger atomicInteger = new AtomicInteger(0);
@Override
public TestCreateAccountRespone getRPC(TestCreateAccountRequest TestCreateAccountRequest) throws TException {
TestCreateAccountRespone TestCreateAccountRespone = new TestCreateAccountRespone();
TestCreateAccountRespone.setCode(1);
TestCreateAccountRespone.setMessage("你好啊");
if (new Random().nextInt(5) > 100) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("getRPC start ...." + TestCreateAccountRequest + "------" + atomicInteger.incrementAndGet());
return TestCreateAccountRespone;
}
Так сервис будет реализован и предоставлен клиенту для использования после регистрации в zookeeper. Стоит отметить, что классы, которые были просканированы и имеют аннотацию @KoalasServer, будут загружены в контекст spring, их можно использовать как обычные spring beans. Также если вы не укажете package, конфигурация будет выглядеть следующим образом:
<koalas:annotation package=""/>
В этом случае реализация будет основана на spring bean, и способ использования должен быть изменён на:
package thrift.annotation.server.impl;
import annotation.KoalasServer;
import org.apache.thrift.TException;
import thrift.domain.TestCreateAccountRequest;
import thrift.domain.TestCreateAccountRespone;
import thrift.service.TestCreateAccountService;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
@KoalasServer(port = 8801, zkpath="127.0.0.1:2181")
@Service
public class TestCreateAccountServiceNettyImpl implements TestCreateAccountService.Iface {
private AtomicInteger atomicInteger = new AtomicInteger(0);
@Override
public TestCreateAccountRespone getRPC(TestCreateAccountRequest TestCreateAccountRequest) throws TException {
TestCreateAccountRespone TestCreateAccountRespone = new TestCreateAccountRespone();
TestCreateAccountRespone.setCode(1);
TestCreateAccountRespone.setMessage("你好啊");
if (new Random().nextInt(5) > 100) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("getRPC start ...." + TestCreateAccountRequest + "------" + atomicInteger.incrementAndGet());
return TestCreateAccountRespone;
}
}
Это всё, что нужно сделать.
``` ```
add ("thrift.domain.TestCreateAccountRequest");
}});
request.setRequestObj (new ArrayList<String>(){{
add ("{\"accountType\":1,\"partnerId\":1,\"partnerName\":\"你好\",\"partnerType\":1,\"poiFlag\":1,\"setAccountType\":true,\"setPartnerId\":true,\"setPartnerName\":true,\"setPartnerType\":true,\"setPoiFlag\":true,\"setSource\":false,\"source\":0}");
}});
String str = genericService.invoke(request);
System.out.println(str);
}
Единственное отличие заключается в том, что необходимо указать аннотацию genericService, и если genericService не пуст, то по умолчанию включается обобщённый вызов.
Конечно, поддерживается и способ Java API.
KoalasClientProxy koalasClientProxy = new KoalasClientProxy();
koalasClientProxy.setServiceInterface("thrift.service.TestCreateAccountService");
koalasClientProxy.setZkPath("127.0.0.1:2181");
koalasClientProxy.setGeneric(true);
koalasClientProxy.setReadTimeout(50000000);
koalasClientProxy.afterPropertiesSet();
GenericService.Iface genericService = (GenericService.Iface) koalasClientProxy.getObject();
GenericRequest request = new GenericRequest();
request.setMethodName("getRPC");
request.setClassType(new ArrayList<String>(){{
add("thrift.domain.TestCreateAccountRequest");
}});
request.setRequestObj(new ArrayList<String>(){{
add("{\"accountType\":1,\"partnerId\":1,\"partnerName\":\"你好\",\"partnerType\":1,\"poiFlag\":1,\"setAccountType\":true,\"setPartnerId\":true,\"setPartnerName\":true,\"setPartnerType\":true,\"setPoiFlag\":true,\"setSource\":false,\"source\":0}");
}});
String str = genericService.invoke(request);
System.out.println(str);
koalasClientProxy.destroy();
Обратите особое внимание на то, что объект KoalasClientProxy очень тяжёлый, и его обязательно нужно уничтожить с помощью метода koalasClientProxy.destroy() при закрытии сервиса, а также необходимо сохранить этот объект в памяти приложения, чтобы не создавать его каждый раз, так как это приведёт к чрезмерной трате ресурсов. Каждому сервису соответствует один объект KoalasClientProxy, который отличается для синхронного и асинхронного использования, и эти пользователи должны обратить на это внимание.
4. Поддержка нативного вызова
В основе koalas-rpc лежит собственный протокол и определённый тип передачи данных, которые могут показаться сложными для понимания тем, кто знаком с исходным кодом. Однако koalas-rpc также поддерживает собственные запросы Thrift во время разработки собственного протокола, что позволяет проводить тестирование на месте. Пример запроса вызова:
package xml.client;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import thrift.domain.TestCreateAccountRequest;
import thrift.domain.TestCreateAccountRespone;
import thrift.service.TestCreateAccountService;
public class ThriftNative {
public static final String SERVER_IP = "localhost";
public static final int SERVER_PORT = 8001;
public public static final int TIMEOUT = 3000000;
public static void main(String[] args) throws TException {
TTransport transport = new TFramedTransport(new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT));
TProtocol protocol = new TBinaryProtocol(transport);
TestCreateAccountService.Client client = new TestCreateAccountService.Client(protocol);
transport.open();
TestCreateAccountRequest request= new TestCreateAccountRequest();
//request.setSource(10);
request.setAccountType(1);
request.setPartnerId(1);
request.setPartnerType(1);
request.setPartnerName("你好啊-我是ThriftNative实现的服务端getRemoteRpc");
request.setPoiFlag(1);
TestCreateAccountRespone respone=client.getRPC(request);
System.out.println(respone);
}
}
``` **Параметры**
| Pool | 50 |
| :-- |:--:|
| minIdle | TCP длинный пул соединений, на основе Apache Pool | 10 |
| lIFO | TCP длинный пул соединений, на основе Apache Pool | true |
| fairness | TCP длинный пул соединений, на основе Apache Pool | false |
| maxWaitMillis | TCP длинный пул соединений, на основе Apache Pool |30 * 1000 |
| timeBetweenEvictionRunsMillis | TCP длинный пул соединений, на основе Apache Pool | 3 * 60 * 1000 |
| minEvictableIdleTimeMillis | TCP длинный пул соединений, на основе Apache Pool | 5 * 60 * 1000 |
| softMinEvictableIdleTimeMillis| TCP длинный пул соединений, на основе Apache Pool | 10 * 60 * 1000 |
| numTestsPerEvictionRun | TCP длинный пул соединений, на основе Apache Pool | 20 |
| testOnCreate | TCP длинный пул соединений, на основе Apache Pool | false |
| testOnBorrow | TCP длинный пул соединений, на основе Apache Pool | false |
| testOnReturn | TCP длинный пул соединений, на основе Apache Pool | false |
| testWhileIdle | TCP длинный пул соединений, на основе Apache Pool | true |
| iLoadBalancer | балансировщик нагрузки, по умолчанию случайный | N |
| env | среда | N, по умолчанию dev |
| removeAbandonedOnBorrow | TCP длинный пул соединений, на основе Apache Pool | true |
| removeAbandonedOnMaintenance | TCP длинный пул соединений, на основе Apache Pool | true |
| removeAbandonedTimeout| TCP длинный пул соединений, на основе Apache Pool | 30000ms |
| maxLength_ | максимальный размер разрешённых к отправке байтов | N, 10 * 1024 * 1024 |
| cores | количество ядер для селектора | N, по умолчанию текущее количество CPU |
| asyncSelectorThreadCount | количество потоков при асинхронном запросе | N, по умолчанию в два раза больше текущего количества CPU |
| privateKey | закрытый ключ | N |
| publicKey | открытый ключ | N |
**2: Сервер**
| Параметры | Описание | Обязательно |
|:--: |:--: |:--:|
| serviceImpl | реализация серверной части | Y |
| serviceInterface | автоматически сгенерированный класс Thrift | Y |
| port | порт, который будет использоваться для раскрытия серверного порта | Y |
| zkpath | путь к ZooKeeper для серверной части | Y |
| cat | (включать ли CAT для просмотра подробной информации о вызовах) | N, по умолчанию false |
| bossThreadCount | число потоков обработки соединений | N, текущее количество ядер CPU |
| workThreadCount | число считывающих потоков | N, в два раза больше текущего количества ядер CPU |
| koalasThreadCount | количество рабочих потоков | 256 |
| maxLength | максимальный объём принимаемых данных | Integer.MAX_VALUE |
| env | окружение | N, dev |
| weight | вес | N, 10 |
| serverType | используемые типы серверов (NETTY и THRIFT, по умолчанию NETTY) | N |
| workQueue | длина очереди для задач при перегрузке сервера | 0 |
| privateKey | закрытый ключ | N |
| publicKey | открытый ключ | N |
##### 1: Клиент-серверное RSA-шифрование
В исходном коде в utils.KoalasRsaUtil есть основной метод main, где уже написан код для генерации приватного и публичного ключей. После выполнения этого кода вы получите четыре длинные строки.
public static String sign(byte[] data, String privateKey) throws Exception { byte[] keyBytes = Base64.decodeBase64 ( privateKey.getBytes ( "UTF-8" ) ); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec ( keyBytes ); KeyFactory keyFactory = KeyFactory.getInstance ( KEY_ALGORITHM ); PrivateKey privateK = keyFactory.generatePrivate ( pkcs8KeySpec ); Signature signature = Signature.getInstance ( SIGNATURE_ALGORITHM ); signature.initSign ( privateK ); signature.update ( data ); return new String ( Base64.encodeBase64 ( signature.sign () ), "UTF-8" ); }
public static boolean verify(byte[] data, String publicKey, String sign) throws Exception { byte[] keyBytes = Base64.decodeBase64 ( publicKey.getBytes ("UTF-8") ); X509EncodedKeySpec keySpec = new X509EncodedKeySpec ( keyBytes ); KeyFactory keyFactory = KeyFactory.getInstance ( KEY_ALGORITHM ); PublicKey publicK = keyFactory.generatePublic ( keySpec ); Signature signature = Signature.getInstance ( SIGNATURE_ALGORITHM ); signature.initVerify ( publicK ); signature.update ( data ); return signature.verify ( Base64.decodeBase64 ( sign.getBytes ("UTF-8") ) ); }
После выполнения метода main вы получите 4 длинные строки, которые можно использовать как приватные и публичные ключи в koalas-rpc для клиентского и серверного взаимодействия с использованием RSA асимметричного шифрования. **Текст запроса:**
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMADFtxxMu67XZXYt7WYjlv7SRkyJDA39ZNK/x3bLQn/BWX7IxaCNmLhzz+QCzykAISIVDyFRSi+agDBx4oR3mHchJJXmUQ/IG37rwPOKc6tIa/ttmEablvCREbswylKABVImPaVZOR/rd+nZ78XAezdYzrixKVt2VQ3/nti1QLpAgMBAAECgYEApwwI/4+b+AYZzRvV967Zazyaw8jTov+MLrC4cokUDfZIBAkQ5awzFKPPYkU3AXLM4ICaiGyJVoESR8ZOitgw1wB6tbI2DhP4FD5dqJkIOdUNujo+gAda3kfeCjAgWbtUL3Zhj7Ff+xFvSDDxUYKGG4fZwge3CFwyQ2vjxhPTXGECQQDpAkS6AW17LvWAiiu2924MEicJQW/s3w+chjuQ3VaauzotAHoSMi8VjBSlINbKxpklthKB4vubfA6AtTHae3hPAkEA0vVBKk9Qz8TkraN3QcILJwHjcjqP8+51n1jimSpZeZQL4BJxStdqqMP2nUzAVnh4ncEoFZ/3QA0sSwcdPtDLRwJBAIDpMmC+HXYDWuvMhbbqWUXwXQxv2Z5xIk/0q8vPyPQ+FUeEdgTPIuGG6H0bF/qDuYL1onOdwpoZHmTy2iwIF10CQBiVNdvNVFhx1EgbtWj3SL9p6+xCTestWnMxO3kuhQVA7j3qJk48jZ43b5JwLbj8pDzaJsgNRMSM6w+klf8duBDz8CQBMIMmhU84An2nv/CPNPArCC8BN8YhY1AH685zgRQBLv5untRhfZ+hJtqjSzTJlY7JHybMzc6wt2FZXrhvuopO4=
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCD0CHPP/sJeYUw0/H0+KwhAP/6cEqnV/HY7q/lA8Ef6oOYlt8QR1LsUxl0ZKP90l2CiS7oEZk9oFeGYIEhy6U6EhWCWcAEyG1Q9qd6KmceGQuYN5mXUwknB202+AiExT2nCQimnbO+T5a5PK8lu8D/XVpUpqxfH9ws0XilE43+XQIDAQAB
**Перевод текста на русский язык:**
В приведённом тексте содержатся четыре строки, которые используются в koalas-rpc для клиентского и серверного взаимодействия с использованием RSA асимметричного ключа. Эти строки можно скопировать и использовать.
Строка 1 и строка 2 соответствуют client private key и public key. Строка 3 и строка 4 соответствуют server private key и public key соответственно. Использование RSA двустороннего шифрования предназначено для защиты важных проектов от несанкционированного доступа со стороны других проектов. В случае неудачной проверки RSA клиент выбрасывает RsaException. RSA симметричное шифрование подходит для использования в трёхсторонних системах и может влиять на производительность передачи данных.
Далее в тексте приводится информация о производительности системы:
* На компьютере mac с процессором 8C и 16G оперативной памяти было проведено тестирование производительности, которое показало, что 10 000 запросов занимают около 12 секунд, а средняя скорость запросов составляет примерно 8000 в секунду. Это свидетельствует о хорошей производительности в кластерной среде.
Также в тексте описывается функциональность системы:
* Для включения функции «Данные большого диска» необходимо установить параметр cat в true на клиенте или сервере. По умолчанию этот параметр установлен в false.
* Версия koalas 2.0 уже поддерживает функцию cat, которая предоставляет статистику QPS, коэффициент использования, TP90line, TP99line и другие настраиваемые параметры мониторинга и оповещения.
* Функция «Цепочка отслеживания» позволяет отслеживать вызовы между системами и определять проблемные участки кода. Эта функция доступна после включения cat.
Для тестирования кода после его загрузки автор предлагает выполнить следующие шаги:
1. Запустить тесты, используя готовые конфигурации XML и аннотации, расположенные в src/test/java и resource.
2. Установить сервис zookeeper перед тестированием.
3. Если не используется сервис обнаружения через zk, можно провести прямое подключение к серверу, указав список серверов и их веса в формате «IP-адрес: порт # вес».
Автор также рекомендует не использовать прямой доступ к серверам в производственной среде, так как это не обеспечивает мониторинг состояния серверов и динамическое добавление и удаление серверов.
Кроме того, в тексте упоминается, что код доступен под лицензией Apache License Version 2.0.
Если у вас есть вопросы или нужна дополнительная информация, вы можете связаться с автором через группу QQ или его блог.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )