пиши на фронт
PRC (удаленный вызов процедуры) Удаленный вызов процедуры. С точки зрения непрофессионала, программа проходитRPCФреймворк вызывает методы на удаленном хосте, как если бы он вызывал локальные методы.DubboтакойRpcFramework, эта статья в основном относится к дизайнерским идеям Dubbo и легко реализует фреймворк Rpc.
Знания, затронутые в этой статье, включают:
- JDK динамический прокси
- сериализация
- связанные с нетти
- Использование зоопарка
1. Платформа RPC
Платформа Rpc обычно делится на три части: реестр (центр регистрации), поставщик (поставщик) и потребитель (потребитель).
- Реестр службы Registry можно реализовать через zookeeper, redis и т.д.
- Провайдер Вызываемый поставщик услуг предоставляет потребителям услуги по вызову
- Потребитель Потребитель, подписавшись на соответствующий сервис, получает ip и номер порта сервиса, который необходимо вызвать для вызова сервиса, предоставляемого удаленным провайдером.
2. Агент
Общие прокси-серверы в java включают динамические прокси-серверы JDK, динамические прокси-серверы Cglib и статические прокси-серверы (технологии байт-кода, такие как ASM).
2.1, JDK-прокси
Например
@Override
@SuppressWarnings("unchecked")
public <T> T createProxyBean(Class<T> rpcServiceInterface) {
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[]{rpcServiceInterface}, new AryaRpcInvocationHandler());
}
Прокси-сервер JDK генерирует прокси-объекты в основном черезjava.lang.reflect.ProxyКатегорияnewProxyInstanceметод. Прокси-серверы JDK требуют, чтобы проксируемый объект реализовывал интерфейс.
2.2, Cglib
Cglib на самом деле представляет собой простую в использовании инкапсуляцию ASM.Cglib не требует от целевого объекта реализации определенного интерфейса и является более гибким, чем динамический прокси JDK.
Enhancer en = new Enhancer();
en.setSuperclass(clazz);
en.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
Object o = method.invoke(object, args);
return o;
}
});
return en.create();
2.3, статический прокси
Изменение файла класса с помощью технологии байт-кода относительно дорого в использовании и изучении.Для того, чтобы использовать его лучше, требуется глубокое понимание структуры файла класса и различных ссылок на символы, поскольку это модификация байт-кода.Таким образом, относительная производительность лучше, чем динамический прокси.
3. Сериализация
Мы знаем, что передача данных по сети осуществляется в виде бинарных потоков. Когда потребитель вызывает провайдера, передаваемые параметры должны быть сначала сериализованы. Когда провайдер получает параметры, его необходимо десериализовать, чтобы получить требуемые данные параметров. Поэтому производительность сериализации оказывает большое влияние на производительность вызова RPC. В настоящее время существует множество основных методов сериализации, в том числе: Kryo, Protostuff и гессиан. Ждать
Protostuff — это реализация с открытым исходным кодом сериализованного Protosbuff от Google. Мы используем его метод сериализации в проекте.
/**
* @author HODO
*/
public class ProtostuffSerializer implements Serializer {
@Override
public byte[] serialize(Object object) {
Class targetClass = object.getClass();
RuntimeSchema schema = RuntimeSchema.createFrom(targetClass);
LinkedBuffer linkedBuffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
return ProtostuffIOUtil.toByteArray(object, schema, linkedBuffer);
}
@SuppressWarnings("unchecked")
@Override
public <T> T deserialize(byte[] bytes, Class<T> targetClass) {
RuntimeSchema schema = RuntimeSchema.createFrom(targetClass);
T object = (T) schema.newMessage();
ProtostuffIOUtil.mergeFrom(bytes, object, schema);
return object;
}
}
4. Нетти
Netty — это высокопроизводительная асинхронная платформа NIO, управляемая событиями, которая поддерживает TCP, UDP и передачу файлов. Например: Код сетевого сервера
public class NettyServer {
private ApplicationContext applicationContext;
public NettyServer(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void init(int port) {
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup worker = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boss, worker);
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
bootstrap.option(ChannelOption.TCP_NODELAY, true);
bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
bootstrap.localAddress(port);
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline channelPipeline = socketChannel.pipeline();
channelPipeline.addLast(new NettyServerHandler(applicationContext));
}
});
ChannelFuture f = bootstrap.bind().sync();
if (f.isSuccess()) {
System.out.println("Netty端口号:" + port);
}
f.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
}
Код клиента Netty
public class NettyClient {
private int port;
private String host;
private final CountDownLatch countDownLatch = new CountDownLatch(1);
SerializerFactory serializerFactory = new SerializerFactory();
Serializer serializer = serializerFactory.getSerialize(ProtostuffSerializer.class);
public NettyClient(String host, int port) {
this.port = port;
this.host = host;
}
public NettyClient(String inetAddress) {
if (inetAddress != null && inetAddress.length() != 0) {
String[] strings = inetAddress.split(":");
this.host = strings[0];
this.port = Integer.valueOf(strings[1]);
}
}
public RpcResponse invoker(RpcRequest rpcRequest) throws InterruptedException {
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
final NettyClientHandler clientHandler = new NettyClientHandler();
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class).option(ChannelOption.SO_KEEPALIVE, true).handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(clientHandler);
}});
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)).sync();
serializer.serialize(rpcRequest);
future.channel().writeAndFlush(Unpooled.buffer().writeBytes(serializer.serialize(rpcRequest)));
countDownLatch.await();
// 等待链接关闭
//future.channel().closeFuture().sync();
return clientHandler.getRpcResponse();
} finally {
eventLoopGroup.shutdownGracefully();
}
}
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
private RpcResponse rpcResponse;
/**
* 接收 Rpc 调用结果
*
* @param ctx netty 容器
* @param msg 服务端答复消息
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
rpcResponse = serializer.deserialize(req, RpcResponse.class);
countDownLatch.countDown();
}
RpcResponse getRpcResponse() {
return rpcResponse;
}
}
}
5. Регистрационный центр зоопарка
выбранzookeeperВ качестве реестра расширения реестра предоставляются в предлагаемой структуре RPC. просто реализоватьRegistryManagerинтерфейс.zookeeperОбщие командные строки:
1. Не указан клиентский скрипт подключения к серверу zookeeper-serverПодключиться к локальной службе по умолчанию
./zkCli -service ip:port
2. Создать
create [-s] [-e] path data acl
создать узел-s -eУкажите тип и характеристики узла соответственно: узлы последовательности и временные узлы создаются по умолчанию как временные узлы, а acl используется для управления разрешениями.
3. Читать
ls pathТолько узлы первого уровня под указанным узлом могут быть просмотрены
get pathПросмотр данных и информации об атрибутах указанного узла
4. Обновить
set path data [version]
Вы можете указать, на какой версии основана операция обновления при обновленииpathВремени не существуетNode does not exist
5. Удалить
`delete path [version]``
6. Пружинная опора
Две аннотации также предоставляются в рамках@RpcConsumerиRpcProviderПросто импортируйте в проект
<dependency>
<groupId>com.yoku.arya</groupId>
<artifactId>arya</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
Внедрение контейнера на стороне провайдера
@Bean
public RpcProviderProcessor rpcProviderProcessor() {
return new RpcProviderProcessor();
}
Инъекция контейнера на стороне потребителя
@Bean
public RpcConsumerProcessor rpcConsumerProcessor() {
return new RpcConsumerProcessor();
}
Полный код проекта aryaGitHub.com/hood OL имеет / ах сотрудников…
Демонстрация использования фреймворкаGitHub.com/hood OL имеет / ах сотрудников…
приветственная звезда
Контакт: gunriky@163.com Если у вас есть какие-либо вопросы, пожалуйста, свяжитесь с нами напрямую