Netty实战:模拟Redis的客户端

简介: Netty实战:模拟Redis的客户端

Netty:模拟Redis的客户端

因为redis是部署在服务器上的 我们只需要模拟客户端发送请求即可所以只需要编写客户端的代码就可以了

前置知识

编写前我们需要知道 redis的请求规范

Redis 的通信 是需要遵循 RESP 协议的

例子:

set hello 123
*3\r\n $3 \r\n set \r\n hello \r\n 123

建立 channel 通道后 发送命令给服务端 此时是写数据【输出】 在出战handler里增加逻辑 当接受响应后 此时数据需要【输入】 存入栈 handler 中 在入栈handler 里增加逻辑

Netty中 Redis 命令对应的类型

  • 单行
  • 错误
  • 整形数字
  • 批量回复
  • 多个批量回复

客户端

我们只需要编写客户端。请求搭建redis的服务器接受和传输数据即可就可以了

客户端还是常见的写法

public class RedisClient {
    private static final String HOST = "xxxxxxxxx";
    private static final int PORT = 6379;
    public static void main(String[] args) {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(bossGroup)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        //  调用netty 提供的支持netty 协议的编解码器
                        //    RedisBulkStringAggregator 和 RedisarrayAggregator 是协议中两种特殊格式的聚合器
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        pipeline.addLast(new RedisDecoder());
                        pipeline.addLast(new RedisBulkStringAggregator());
                        pipeline.addLast(new RedisArrayAggregator());
                        pipeline.addLast(new RedisEncoder());
                        // 我们自己的处理器
                        pipeline.addLast(new RedisClientHandler());
                    }
                });
        try {
            ChannelFuture syncFuture = bootstrap.connect(HOST, PORT).sync();
            System.out.println("enter redis commands");
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
            for (; ; ) {
                String input = bufferedReader.readLine();
                //退出任务
                if ("quit".equals(input)) {
                    syncFuture.channel().close().sync();
                    break;
                }
                syncFuture.channel().writeAndFlush(input).sync();
            }
            syncFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
        }
    }
}

处理器

因为要读取和写入 所以我们需要集成混合处理器类 : ChannelDuplexHandler

我们需要判断五种请求类型 所以先封装一个类别输出的方法

RedisMessage Netty提供的redis的信息对象,以下五种类型都来自于它

private void printRedisResponse(RedisMessage msg) {
        if (msg instanceof SimpleStringRedisMessage) {
            SimpleStringRedisMessage tmpMsg = (SimpleStringRedisMessage) msg;
            System.out.println(tmpMsg.content());
        } else if (msg instanceof ErrorRedisMessage) {
            ErrorRedisMessage tmpMsg = (ErrorRedisMessage) msg;
            System.out.println(tmpMsg.content());
        } else if (msg instanceof IntegerRedisMessage) {
            IntegerRedisMessage tmpMsg = (IntegerRedisMessage) msg;
            System.out.println(tmpMsg.value());
        } else if (msg instanceof FullBulkStringRedisMessage) {
            FullBulkStringRedisMessage tmpMsg = (FullBulkStringRedisMessage) msg;
            if (tmpMsg.isNull()) {
                return;
            }
            System.out.println(tmpMsg.content().toString(CharsetUtil.UTF_8));
        } else if (msg instanceof ArrayRedisMessage) {
            ArrayRedisMessage tmpMsg = (ArrayRedisMessage) msg;
            for (RedisMessage child : tmpMsg.children()) {
                printRedisResponse(child);
            }
        }
        // 如果都是不是应该抛出异常
    }

写命令

// 写
    // 出栈handler 的常用方法
    //需要处理redis 命令
    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        // 键盘传入的字符串 如 : keys *
        String commandStr = (String) msg;
        // 通过空格来分离出命令
        String[] commandArr = commandStr.split("\\s+");
        // 接受redis 命令的列表  RedisMessag保存命令的内容
        List<RedisMessage> redisMessageList = new ArrayList<>(commandArr.length);
        for (String cmdStr : commandArr) {
            FullBulkStringRedisMessage message = new FullBulkStringRedisMessage(
                    ByteBufUtil.writeUtf8(ctx.alloc(), cmdStr));
            redisMessageList.add(message);
        }
        //将分离的命令 合并成一个完整的命令
        RedisMessage request = new ArrayRedisMessage(redisMessageList);
        //写入通道
        ctx.write(request, promise);
    }

读取命令

// 读取
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    // 此时接受的时候这个值 就是我们存储redismessage 的对象
    RedisMessage redisMessage = (RedisMessage) msg;
    // 返回的结果是不同类型 分开进行处理
    printRedisResponse(redisMessage);
    //    内存管理使用了 引用计数的方式 所以我们需要释放资源
    ReferenceCountUtil.release(redisMessage);
}

演示效果

目录
相关文章
|
5月前
|
存储 NoSQL 前端开发
Redis专题-实战篇一-基于Session和Redis实现登录业务
本项目基于SpringBoot实现黑马点评系统,涵盖Session与Redis两种登录方案。通过验证码登录、用户信息存储、拦截器校验等流程,解决集群环境下Session不共享问题,采用Redis替代Session实现数据共享与自动续期,提升系统可扩展性与安全性。
348 3
Redis专题-实战篇一-基于Session和Redis实现登录业务
|
5月前
|
存储 缓存 NoSQL
Redis专题-实战篇二-商户查询缓存
本文介绍了缓存的基本概念、应用场景及实现方式,涵盖Redis缓存设计、缓存更新策略、缓存穿透问题及其解决方案。重点讲解了缓存空对象与布隆过滤器的使用,并通过代码示例演示了商铺查询的缓存优化实践。
272 1
Redis专题-实战篇二-商户查询缓存
|
11月前
|
数据采集 存储 数据可视化
分布式爬虫框架Scrapy-Redis实战指南
本文介绍如何使用Scrapy-Redis构建分布式爬虫系统,采集携程平台上热门城市的酒店价格与评价信息。通过代理IP、Cookie和User-Agent设置规避反爬策略,实现高效数据抓取。结合价格动态趋势分析,助力酒店业优化市场策略、提升服务质量。技术架构涵盖Scrapy-Redis核心调度、代理中间件及数据解析存储,提供完整的技术路线图与代码示例。
1181 0
分布式爬虫框架Scrapy-Redis实战指南
|
8月前
|
缓存 监控 NoSQL
Redis 实操要点:Java 最新技术栈的实战解析
本文介绍了基于Spring Boot 3、Redis 7和Lettuce客户端的Redis高级应用实践。内容包括:1)现代Java项目集成Redis的配置方法;2)使用Redisson实现分布式可重入锁与公平锁;3)缓存模式解决方案,包括布隆过滤器防穿透和随机过期时间防雪崩;4)Redis数据结构的高级应用,如HyperLogLog统计UV和GeoHash处理地理位置。文章提供了详细的代码示例,涵盖Redis在分布式系统中的核心应用场景,特别适合需要处理高并发、分布式锁等问题的开发场景。
527 41
|
8月前
|
机器学习/深度学习 存储 NoSQL
基于 Flink + Redis 的实时特征工程实战:电商场景动态分桶计数实现
本文介绍了基于 Flink 与 Redis 构建的电商场景下实时特征工程解决方案,重点实现动态分桶计数等复杂特征计算。通过流处理引擎 Flink 实时加工用户行为数据,结合 Redis 高性能存储,满足推荐系统毫秒级特征更新需求。技术架构涵盖状态管理、窗口计算、Redis 数据模型设计及特征服务集成,有效提升模型预测效果与系统吞吐能力。
907 10
|
11月前
|
缓存 NoSQL Java
基于SpringBoot的Redis开发实战教程
Redis在Spring Boot中的应用非常广泛,其高性能和灵活性使其成为构建高效分布式系统的理想选择。通过深入理解本文的内容,您可以更好地利用Redis的特性,为应用程序提供高效的缓存和消息处理能力。
1076 79
|
8月前
|
缓存 NoSQL 算法
高并发秒杀系统实战(Redis+Lua分布式锁防超卖与库存扣减优化)
秒杀系统面临瞬时高并发、资源竞争和数据一致性挑战。传统方案如数据库锁或应用层锁存在性能瓶颈或分布式问题,而基于Redis的分布式锁与Lua脚本原子操作成为高效解决方案。通过Redis的`SETNX`实现分布式锁,结合Lua脚本完成库存扣减,确保操作原子性并大幅提升性能(QPS从120提升至8,200)。此外,分段库存策略、多级限流及服务降级机制进一步优化系统稳定性。最佳实践包括分层防控、黄金扣减法则与容灾设计,强调根据业务特性灵活组合技术手段以应对高并发场景。
2302 7
|
9月前
|
算法 Java 容器
Netty源码—4.客户端接入流程
本文主要介绍了关于Netty客户端连接接入问题整理、Reactor线程模型和服务端启动流程、Netty新连接接入的整体处理逻辑、新连接接入之检测新连接、新连接接入之创建NioSocketChannel、新连接接入之绑定NioEventLoop线程、新连接接入之注册Selector和注册读事件、注册Reactor线程总结、新连接接入总结
|
JSON NoSQL Java
【Redis】2、Redis 的 Java 客户端(Jedis 和 SpringDataRedis)
【Redis】2、Redis 的 Java 客户端(Jedis 和 SpringDataRedis)
705 0
|
JSON NoSQL Java
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
这篇文章介绍了在Java中使用Redis客户端的几种方法,包括Jedis、SpringDataRedis和SpringBoot整合Redis的操作。文章详细解释了Jedis的基本使用步骤,Jedis连接池的创建和使用,以及在SpringBoot项目中如何配置和使用RedisTemplate和StringRedisTemplate。此外,还探讨了RedisTemplate序列化的两种实践方案,包括默认的JDK序列化和自定义的JSON序列化,以及StringRedisTemplate的使用,它要求键和值都必须是String类型。
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)