《Netty、Redis、Zookeeper高并发实战》1️⃣高并发时代的必备技能


高并发时代已经到来,Netty、Redis、ZooKeeper是高并发时代的必备工具

1、Netty为何这么火

        Netty是JBOSS提供的一个Java开源框架,是居于NIO的客户端/服务器编程框架,它既能快速开发高并发、高可用、高可靠性的网络服务器程序,也能开发高可用、高可靠的客户端程序

        注:NIO是指非阻塞输入输出(Non-Blocking IO),也称非阻塞IO

1.1 Netty火热的程度

        火爆的Kafka、RocketMQ等消息中间件、火热的ElasticSearch开源搜索引擎、大数据处理Hadoop的RPC框架Avro、主流的分布式通信框架Dubbo,它们都使用了Netty

        Netty之所以受青睐,是因为Netty提供异步的、事件驱动的网络应用程序框架和工具。作为一个异步框架,Net特有的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便地主动获取或者通过通知机制获得IO操作结果

        与JDK原生NIO相比,Netty提供了相对十分简单易用的API,因为非常适合网络编程。Netty主要是基于NIO来实现的,在Netty中也可以提供阻塞IO的服务

优点:

  • API使用简单,开发门槛低
  • 功能强大,预置了多种编解码功能,支持多种主流协议
  • 定制能力强,可以通过ChannelHandler对通信框架进行灵活扩展
  • 性能高,与其他业界主流的NIO框架对比,Netty的总和性能最优
  • 成熟、稳定,Netty修复了已经发现的所有JDK NIO中的BUG,业务开发人员不需要再为NIO的BUG而烦恼
  • 社区活跃,版本迭代周期短,发现的BUG可以被即时修复

1.2 Netty是面试的必杀器

        Netty是互联网中间件领域使用最广泛、最核心的网络通信框架之一

2、高并发利器Redis

        任何高并发的系统,不可或缺的就是缓存。Redis缓存目前已经成为缓存的事实标准

2.1 什么是Redis

        Redis是Remote Dictionary Server(远程字典服务器)的缩写,最初是作为数据库的工具来使用的。是目前使用广泛、高效的一款开源缓存。Redis使用C语言开发,将数据保存在内存中,可以看成是一款纯内存的数据库,所以它的数据存取速度非常快。一些经常用并且创建时间较长的内容,可以缓存到Redis中,而应用程序能以极快的速度存取这些内容

        Redis通过键-值对(Key - Value Pair)的形式来存取数据,类似于Java中的Map映射。Redis的Key键,只能是String字符串类型。Redis的Value值类型包括:string字符类型、map映射类型、list列表类型、set集合类型、sortedset有序集合类型

        Redis的主要应用场景:缓存(数据查询、短连接、新闻内容、商品内容等)、分布式会话(Session)、聊天室的在线好友列表、任务队列(秒杀、抢购、12306等)、应用排行榜、访问统计、数据过期处理(可以精确到毫秒)

2.2 Redis成为缓存事实标准的原因

        相对于其他的键-值对(Key - Value)内存数据库(如Memcached)而言,Redis具有如下特点:

  1. 速度快
    不需要等待磁盘的IO,在内存之间进行的数据存储和查询,速度非常快。当然,缓存的数据总量不能太大,因为受到物理内存空间大小的限制
  2. 丰富的数据结构
    除了string之外,还有list、hash、set、sortedset,一共五种类型
  3. 单线程,避免了线程切换和锁机制的性能消耗
  4. 可持久化
    支持RDB于AOF两种方式,将内存中的数据写入外部的物理存储设备
  5. 支持发布 / 订阅
  6. 支持Lua脚本
  7. 支持分布式锁
    在分布式系统中,如果不同的节点需要访问到一个资源,往往需要通过互斥机制来防止彼此干扰,并且保证数据的一致性。在这种情况下,需要使用到分布式锁。分布式锁和Java的锁用于实现不同线程之间的同步访问,原理上是类似的
  8. 支持原子操作和事务
    Redis事务是一组命令的集合。一个事务中的命令要么都执行,要么都不执行。如果命令在运行期间出现错误,不会自动回滚
  9. 支持住 - 从(Master-Slave)复制与高可用(Redis Sentinel)集群(3.0 版本以上)
  10. 支持管道
    Redis管道是指客户端可以将多个命令一次性发送到服务器,然后由服务器一次性返回所有结果。管道技术的优点是:在批量执行命令的应用场景中,可以大大减少网络传输的开销,提高性能

3、分布式利器Zookeeper

        突破了单体瓶颈之后的高并发,就必须靠集群了,而集群的分布式架构和协调,一定少不了可靠的分布式协调工具,Zookeeper就是目前结尾中的分布式协调工具

3.1 什么是Zookeeper

        起源于雅虎。Zookeeper的功能,正好是用来协调分布式环境的,协调各个以动物命名的分布式组件

3.2 Zookeeper的优势

        Zookeeper对不同系统环境的支持都很好

        Zookeeper的核心优势是,实现了分布式环境的数据一致性,简单地说:每时每刻我们访问Zookeeper的树结构时,不同的节点返回的数据都是一致的。也就是说,对Zookeeper进行数据访问时,无论是什么时间,都不会引起脏读、重复读。注:脏读是指在数据库存取中无效数据的读出

        Zookeeper提供的功能都是分布式系统中非常底层且必不可少的基本功能,如果开发者自己来实现这些功能而且要达到高吞吐、低延迟同时的还要保证一致性和可用性,实际上是非常困难的。因此,借助Zookeeper提供的这些功能,开发者就可以轻松在Zookeeper之上构建自己的各种分布式系统

4、高并发IM的综合实践

        应用Netty、Redis、Zookeeper持续迭代一个高并发学习项目,叫做“CrazyIM”

4.1 高并发IM(即时通讯)的学习价值

        一个分布式、高并发的IM系统,面临的QPS(Query Per Second,每秒查询率)峰值可能在十万、百万、千万,甚至上亿级别。对于此纵深层次化的、递进的高并发需求,将无极限地考研着系统的性能。需要不断地从通信协议、到系统的架构进行优化,对技术能力是一种非常极致的考验和训练

        具有不同的QPS峰值规模的IM系统而言,它们所处的用户需求环境是不一样的。也就是说,IM系统综合性相对较强,相关的技术需要覆盖到满足各种不同应用场景的网络传输、分布式协调、分布式缓存、服务化架构等

4.2 庞大的应用场景

        高并发IM典型的应用场景如下:私信、聊天、大规模推送、视频会议、弹幕、抽奖、互动游戏、基于位置的应用(Uber、滴滴司机位置)、在线教育、智能家居等,如下图所示
在这里插入图片描述

图1-1 高并发IM典型的应用场景

        尤其是对于APP开发的小伙伴们来说,IM已经成为大多数APP的标配。在移动互联网时代,推送(Push)服务成为APP应用不可或缺的重要组成部分,推送服务可以提升用户的活跃度和留存率。我们的手机每天接收到各种各样的广告和提示信息等,它们大多数都是通过推送服务实现的

        随着5G时代物联网的发展,未来所有接入物联网的智能设备,都将是IM系统的客户端,这就意味着推送服务会在未来面临海量的设备和终端接入。为了支持这些千万级、上亿级的终端,一定是需要强悍的后台系统

5、Netty、Redis、Zookeeper实践计划

        从最基础的NIO入手,列出一个大致12天的实践计划,深入掌握Netty、Redis、Zookeeper

5.1 第1天:Java NIO实践

实践一:使用FileChannel复制文件

        通过使用Channel通道,完成复制文件

        本节掌握:Java NIO中ByteBuffer、Channel两个重要组件的使用

        使用文件Channel通道的transferFrom方法,完成高效率的文件复制

实践二:使用SocketChannel传输文件

        本节掌握以下知识:

  • 非阻塞客户端在发起连接后,需要不断的自旋,检测连接是否完成的
  • SocketChannel传输管道的reaf读取办法、write写入方法
  • 在SocketChannel传输管道关闭前,尽量发送一个输出结束标志到对方端

实践三:使用DatagramChannel传输数据

        客户端使用Datagramchannel发送数据,服务器端使用DatagramChannel接收数据

        本节掌握以下知识:

  • 使用接收数据方法receive,使用发送数据方法send
  • DatagramChannel和SocketChannel两种通道,在发送、接收数据上的不同

实践四:使用NIO实现Discard服务器

        客户端功能:发送一个数据包到服务器端,然后关闭连接。服务器端也很简单,收到客户端的数据,直接丢弃

        本节掌握以下知识:

  • Selector选择器的注册,以及选择器的查询
  • SelectionKey选择键方法的使用
  • 根据SelectionKey方法的四种IO事件类型,完成对应的IO的处理

5.2 第2天:Reactor反应器模式实践

实践一:单线程Reactor反应器模式的实现

        使用单线程Reactor反应器模式,设计和实现一个EchoServer回显服务器。功能很简单:服务器端读取客户端的输入,然后回显到客户端

        本节掌握以下知识:

  • 单线程Reactor反应器模式两个重要角色——Reactor反应器、Handler处理器的编写
  • SelectionKey选择键两个重要的方法——attach和attachment方法的使用

实践二:多线程Reactor反应器模式

        使用多线程Reactor反应器模式,设计一个EchoServer回显服务器,主要的升级方式为:

  • 引入ThreadPool线程池,将负责IOHandler输入输出处理器的执行,放入独立的线程池中,与负责服务监听和IO实践查询的反应器线程相隔离
  • 将反应器线程拆分为多个SubReactor子反应器线程,同时,引入多个Selector选择器,每一个子反应器线程负责一个选择器读取客户端的输入,回显到客户端

        本节掌握以下知识:

  • 线程池的使用
  • 多线程反应器模式的实现

5.3 第3天:异步回调模式实践

实践一:使用线程join方式,通过阻塞式异步调用的方式,实现泡茶喝的实例

        泡茶喝的三条线程:主线程、清晰线程、烧水线程

  • 主线程(Main Thread) 的工作是:启动清洗线程、启动烧水线程,等清洗、烧水的工作完成后,泡茶喝
  • 清洗线程(WashThread) 的工作是:洗茶壶、洗茶杯
  • 烧水线程(HotWater) 的工作是:洗好水壶,灌上凉水,放在火上,一直等水烧开

        本节掌握以下知识:

  • 不同的版本的join方法的使用

实践二:使用FutureTask类和Callable接口,启动阻塞式的异步调用,并且获取异步线程的结果

        将实践一改进成如下:

  • 主线程(MainThread) 的工作是:启动清洗线程、启动烧水线程,然后阻塞,等待异步线程的返回值,决定后续的动作
  • 清洗线程(WashThread) 在异步执行完成之后,有返回值
  • 烧水线程(HotWaterThread) 在异步执行完成之后,有返回值

        本节掌握以下知识:

  • Callable(可调用)接口的使用;Callable接口和Runnable(可执行)接口的不同
  • FutureTash异步任务类的使用

实践三:使用ListenableFuture类和FutureCallback接口,启动非阻塞异步调用,并且完成异步回调

        继续改进如下:

  • 主线程(MainThread) 的工作是:启动清洗线程、启动烧水线程,并且设置异步完成后的回调方法,这里主线程不阻塞等待,而是去干其他事情,例如读报纸
  • 清洗线程(WashThread) 在异步执行完成之后,执行回调方法
  • 烧水线程(HotWaterThread) 在异步执行完成后,执行回调方法

        本节掌握以下知识:

  • FutureCallback接口的使用;FutureCallback接口和Callable接口的区别和联系
  • ListenableFuture异步任务类的使用,以及为异步任务设置回调方法

5.4 第4天:Netty基础实践

实践一:Netty中Handler处理器的生命周期

操作步骤如下:

步骤01:
        定义一个非常简单的入站处理器——InHandlerDemo。这个类继承于ChannellnboundHandlerAdapter适配器,它实现了基类的所有的入站处理方法,并在每一个方法的实现中,都加上了必要的输出信息

步骤02:
        编写一个单元测试代码:将这个处理器加入到一个EmbeddedChannel嵌入式通道的流水线中

步骤03:
        通过writeInbound方法,向EmbeddedChannel写一个模拟的入站ByteBuf数据包。InHandlerDemo作为一个入站处理器,就会处理到该ByteBuf数据包

步骤04:
        通过输出,可以观测到处理器的生命周期

        本节掌握以下知识:

  • Netty中Handler处理器的生命周期
  • EmbeddedChannel嵌入式通道的使用

实践二:ByteBuf的基本使用

操作步骤如下:

步骤01:
        使用Netty的默认分配器,分配了一个初始容量为9个字节,最大上限为100个字节的ByteBuf缓冲区

步骤02:
        向ByteBuf写数据,观测ByteBuf的属性变化

步骤03:
从ByteBuf读数据,观测ByteBuf的属性变化

        本节掌握以下知识:

  • ByteBuf三个重要属性:readerIndex(读指针)、writerIndex(写指针)、maxCapacity(最大容量)
  • ByteBuf读写过程中,以上三个重要属性的变化规律

实践三:使用Netty,实现EchoServer回显服务器

        服务器读取客户端的输入,然后将数据包直接回显到客户端

        本节掌握以下知识:

  • 服务器端ServerBootstrap的装配和使用
  • 服务器端NettyEchoServerHandler入站处理器的channelRead入站处理方法的编写
  • 服务器端实现Netty的ByteBuf缓冲区的读取、回显
  • 客户端Bootstrap的装配和使用
  • 客户端NettyEchoClientHandler入站处理器中接收回显的数据,并且释放内存
  • 客户端实现多种方式释放ByteBuf,包括:自动释放、手动释放

5.5 第5天:解码器(Decoder)与编码器(Encoder)实践

实践一:整数解码实践

具体步骤如下:

步骤01:
        定义一个非常简单的整数解码器——Byte2IntegerDecoder。这个类继承于ByteToMessageDecoder字节码解码抽象类,并实现基类的decode抽象方法,将ByteBuf缓冲区中的数据,解码成以一个一个的Integer对象

步骤02:
        定义一个非常简单的整数处理器——IntegerProcessHandler。读取上一站的入站数据,把它转换成整数,并且显示在Console控制台

步骤03:
        编写一个整数解码实战的测试用例。在测试用例中,新建了一个EmbeddedChannel嵌入式的通道实例,将两个自己的入站处理器Byte2IntegerDecoder、IntegerProcessHandler加入到通道的流水线上。通过writeInbound方法,向EmbeddedChannel写入一个模拟的入站ByteBuf数据包

步骤04:
        通过输出,可以观察整数解码器的解码结果

        本节掌握以下知识:

  • 如何基于Netty的ByteToMessageDecoder字节码解码抽象类,实现自己的ByteBuf二进制字节到POJO对象的解码
  • 使用ByteToMessageDecoder,如何管理ByteBuf的应用计数

实践二:整数相加的解码器实践

具体步骤如下:

步骤01:
        继承ReplayingDecoder基础解码器,编写一个整数相加的解码器:一次解码两个整数,并把这两个数据相加之和,作为解码的结果

步骤02:
        使用前面定义的整数处理器——IntegerProcessHandler。读取上一站的入站数据,把它转换成整数,并且显示在Console控制台

步骤03:
        使用前面定义的测试类,测试整数相加的解码器,并且查看结果是否正确

        本节掌握以下知识:

  • 如何基于ReplayingDecoder解码器抽象类,实现自己的ByteBuf二进制字节到POJO对象的解码
  • ReplayingDecoder的成员属性——state阶段属性的使用
  • ReplayingDecoder的重要方法——checkpoint(IntegerAddDecoder.Status)方法的使用

实践三:基于Head-Content协议的字符串分包解码器

具体步骤如下:

步骤01:
        继承ReplayingDecoder基础解码器,编写一个字符串分包解码器StringReplayDecoder

        在StringReplayDecoder的decode方法中,分两步:第1步,解码出字节串的长度;第2步,按照第一个阶段的字节串长度,解码出字符串的内容

步骤02:
        编写一个简单的业务处理器StringProcessHandler。其功能是:读取上一站的入站数据,把它转换成字符串,并且显示在Console控制台

步骤03:
        新建了一个EmbeddedChannel嵌入式的通道实例,将两个自己的入站处理器StringReplayDecoder、StringProcessHandler加入到通道的流水线上。为了测试入站处理器,使用writeInbound方法,向嵌入式通道EmbeddedChannel写入了100个ByteBuf入站数据后,pipeline流水线上的两个入站处理器,就能不断地处理这些入站数据:将接收到的二进制字节,解码成一个一个的字符串,然后逐个地显示在Console控制台上

        本节掌握以下知识:

  • 如何基于ReplayingDecoder解码器抽象类,实现自己的ByteBuf二进制字节到字符串的解码
  • 巩固ReplayingDecoder的成员属性——state阶段属性的使用
  • 巩固ReplayingDecoder的重要方法——checkpoint(IntegerAddDecoder.Status)方法的使用

实践四:多字段Head-Content协议数据包解析实践

具体步骤如下

步骤01:
        使用LengthFieldBasedFrameDecoder解码器,解码复杂的Head-Content协议。例如协议中包含版本号、魔术等多个其他的数据字段

步骤02:
        使用前面所编写那一个简单的业务处理器StringProcessHandler。其功能是:读取上一站的入站数据,把它转换成字符串,并且显示在Console控制台上

步骤03:
        新建一个EmbeddedChannel嵌入式的通道实例,将第一步和第二步的两个入站处理器LengthFieldBasedFrameDecoder、StringProcessHandler加入到通道的流水线上。为了测试入站处理器,使用writeInbound方法,想嵌入式通道EmbeddedChannel写入100个ByteBuf入站缓冲;每一个ByteBuf缓冲,仅仅包含一个字符串。EmbeddedChannel通道接收到入站数据后,pipeline流水线上的两个入站处理器,就能不断地处理到这些入站数据:将接到的二进制字节,解码成一个一个的字符串,然后逐个地显示在控制台上

        本节掌握以下知识:

  • LengthFieldBasedFrameDecoder解码器的使用
  • LengthFiledBasedFrameDecoder解码器的长度的矫正公式,计算公式为:内容字段的偏移-长度字段的偏移-长度字段的长度

5.6 第6天:JSON和ProtoBuf序列化实践

实践一:JSON通信实践

        客户端将POJO转成JSON字符串,编码后发送到服务器端。服务器端接收客户端的数据包,并解码成JSON,转成POJO

具体步骤如下:

步骤01:
        客户端的编码过程:
        先通过谷歌的Gson框架,将POJO序列化成JSON字符串;然后使用Netty内置的StringEncoder编码器,将JSON字符串编码成二进制字节数组;最后,使用LengthFieldPrepender编码器(Netty内置) ,将二进制字节数组编码成Head-Content格式的二进制数据包。

步骤02:
        服务器端的解码过程:
        先使用LengthFieldBasedFrameDecoder (Netty内置的自定义长度数据包解码器)解码Head-Content二进制数据包,解码出Content字段的二进制内容。

        然后,使用StringDecoder字符串解码器(Netty内置的解码器) ,将二进制内容解码成JSON字符串。

        最后,使用自定义的JsonMsgDecoder解码器,将JSON字符串解码成POJO对象。

步骤03:
        编写一个JsonMsgDecoder自定义的JSON解码器。将JSON字符串,解码成特定的POJO对象。

步骤04
        分别组装好服务器端、客户端的流水线,运行程序,查看两端的通信结果。

本环节的目标是掌握以下知识:

  • LengthFieldPrepender编码器的使用:在发送端使用它加上Head-Content的头部长度。
  • JsonMsgDecoder的编写。
  • JSON传输时,客户端流水线编码器的组装,服务器端流水线解码器的组装。

实践二:ProtoBuf通信实践

        设计一个简单的客户端/服务器端传输程序:客户端将ProtoBuf的POJO编码成二进制数据包,发送到服务器端;服务器端接收客户端的数据包,并解码成ProtoBuf的POJO

具体步骤如下:

步骤01:
        设计好需要传输的ProtoBuf的".proto"协议文件,并且生成ProtoBuf的POJO和Builder:

        在".proto"协议文件中,仅仅定义了一个消息结构体,并且该消息结构体也非常简单,只包含两个字段:消息ID、消息内容。

        使用protobuf-maven-plugin插件,生成message的POJO类和Builder (构造者)类的Java代码。

步骤02:
        客户端的编码过程:先使用Netty内置的ProtobufEncoder,将ProtobufPOJO对象编码成二进制的字节数组。

        然后,使用Netty内置的ProtobufVarint32LengthFieldPrepender编码器,加上varint32格式的可变长度。

        Netty会将完成了编码后的Length+Content格式的二进制字节码,发送到服务器端。

步骤03:
        服务器端的解码过程:

        先使用Netty内置的ProtobufVarint32FrameDecoder,根据varint32格式的可变长度值,从入站数据包中,解码出二进制Protobuf字节码。

        然后,可以使用Netty内置的ProtobufDecoder解码器,将Protobuf字节码解码成Protobuf POJO对象。

        最后, 自定义一个ProtobufBussinessDecoder解码器,处理ProtobufPOJO对象。

本环节的目标是掌握以下知识:

  • proto"基础协议。
  • Netty内置的ProtobufEncoder,ProtobufDecoder两个专用的传输Protobuf序列化数据的编码器/解码器的使用。
  • Netty内置的两个ProtoBuf专用的可变长度Head-Content协议的半包编码、解码处理器:ProtobufVarint32LengthFieldPrepender编码器ProtobufVarint32FrameDecoderProtobufEncoder解码器的使用。

5.7 第7~10天:基于Netty的单聊实战

实践一:自定义ProtoBuf编码器/解码器

具体步骤如下

步骤01
        为单聊系统,设计一套自定义的".proto"协议文件;然后通过maven插件生成Protobuf Builder和POJO

步骤02
        继承Netty提供的MessageToByteEncoder编码器,编写一个自定义的Protobuf编码器,完成Head-Content协议的复杂数据包的编码。

        通过自定义编码器,最终将ProtobufPOJO编码成Head-Content协议的二进制ByteBuf帧。

步骤03
        继承Netty提供的ByteToMessageDecoder解码器,编写一个自定义的Protobuf解码器,完成Head-Content协议的复杂数据包的解码。

        通过自定义的解码器,最终将Head-Content协议的复杂数据包,解码出ProtobufPOJO

步骤04
        分别组装好服务器端、客户端的流水线,运行程序,查看两端的通信结果。

本环节的目标是掌握以下知识:

  • 设计复杂的".proto"协议文件。
  • 自定义的Protobuf编码器的编写。
  • 自定义的Protobuf编码器的编写。

实践二:登录实践

业务逻辑:

  • 客户端发送登录数据包。
  • 服务器端进行用户信息验证。
  • 服务器端创建Session会话。
  • 服务器端将登录结果信息返回给客户端,包括成功标志、Session ID等。

具体步骤如下:

从客户端到服务器端再到客户端,大致有以下几个步骤。

步骤01
        编写LoginConsoleCommand控制台命令类,从客户端收集用户ID和密

步骤02
        编写客户端LoginSender发送器类,组装Protobuf数据包,通过客户端通道发送到服务器端。

步骤03
        编写服务器端UserLoginHandler入站处理器,处理收到的登录消息,完成数据的校验后,将数据包交给业务处理器LoginMsgProcesser,进行异步的处理。

步骤04
        编写服务器端LoginMsgProcesser (业务处理器) ,将处理结果,写入用户绑定的子通道。

步骤05
        编写客户端业务处理器LoginResponceHandler,处理登录响应,例如设置登录的状态,保存会话的SessionID等。

本环节的目标是掌握以下知识:

  • Netty知识的综合运用。
  • Channel通道容器功能的使用。

实践三:单聊实践

单聊的业务逻辑:

  • 当用户A登录成功之后,按照单聊的消息格式,发送所要的消息。
  • 这里的消息格式设定为–userld:content,其中的userld,就是消息接收方目标用户B的userld;其中的content,表示聊天的内容
  • 服务器端收到消息后,根据目标userld,进行消息帧的转发,发送到用户B所在的客户端。
  • 客户端用户B收到用户A发来的消息,显示在自己的控制台上。

具体步骤如下:

        从客户端到服务器端再到客户端,大致有5个步骤。

步骤01
        当用户A登录成功之后,按照单聊的消息格式,发送所要的消息。

        这里的消息格式设定为-userld:content,其中的userld,就是消息接收方目标用户B的userld,其中的content,表示聊天的内容。

步骤02
        CommandController在完成聊天内容和目标用户的收集后,调用chatSender发送器实例,将聊天消息组装成Protobuf消息帧,通过客户端channel通道发往服务器端

步骤03
        编写服务器端的消息转发处理器ChatRedirectHandler类,其功能是,对用户登录进行判断:如果没有登录,则不能发送消息;开启异步的消息转发,由负责转发的chatRedirectProcesser实例,完成消息转发。

步骤04
        编写负责异步消息转发的ChatRedirectProcesser类,功能如下:根据目标用户ID,找出所有的服务器端的会话列表(Session List) ,然后对应每一个会话,发送一份消息

步骤05
        编写客户端ChatMsgHandler处理器,主要的工作如下:对消息类型进行判断,判断是否为聊天请求Protobuf数据包。如果不是,直接将消息交给流水线的下一站;如果是聊天消息,则将聊天消息显示在控制台上。

本环节目标是掌握以下知识:

  • Netty知识的综合运用。
  • 服务器端会话(Session)的管理。

5.8 第11天:Zookeeper实践计划

实践一:分布式ID生成器

具体步骤如下:

步骤01
        白定义一个分布式ID生成器-IDMaker类,通过创建ZK的临时顺序节点的方法,生成全局唯一的ID。

步骤02
        基于自定义的IDMaker,编写单元测试的用例,生成ID

本环节的目标是掌握以下知识:

  • 分布式ID生成器原理。
  • ZooKeeper客户端的使用。

实践二:使用ZK实现SnowFlake ID算法

具体步骤如下:

步骤01
        编写一个实现SnowFlake ID算法的ID生成器SnowflakeldGenerator类,生成全局唯一的ID

步骤02
        基于自定义的SnowflakeldGenerator,编写单元测试的用例,生成ID

本环节的目标是掌握以下知识:

  • SnowFlake ID算法原理。
  • ZooKeeper客户端的使用。

5.9 第12天:Redis实践计划

实践一:使用RedisTemplate模板类完成Redis的缓存CRUD操作

具体步骤如下:

步骤01
        将RedisTemplate模板类的大部分缓存操作,封装成一个自己的缓作Service服务,称之为CacheOperationService类。

步骤02
        编写业务类UserServicelmplWith Template类,使用CacheOperationService类,完成User对象的缓存CRUD。

步骤03
        编写测试用例,访问UserServicelmplWith Template类。观察在进User对象的查询时,能优先使用缓存数据,是否省去数据库访问的时间。

本环节目标是掌握以下知识:

  • Redis Template模板类的使用。
  • Jedis的客户端API
  • Redis Template模板API

实践二:使用RedisTemplate模板类完成Redis的缓存CRUD操作

具体步骤如下:

步骤01
        使用RedisCallback的dolnRedis回调方法,在dolnRedis回调方法中,直接使用实参RedisConnection连接类实例,完成Redis的操作。

步骤02
        编写业务类UserServicelmpllnTemplate类,使用Redis Template模板实例去执行RedisCallback回调实例,完成User对象的缓存CRUD

步骤03
        编写测试用例,访问UserServicelmplInTemplate类。观察在进行User对象的查询时,优先使用缓存数据,看看是否省去了数据库访问的时间。

本环节的目标是掌握以下知识:

  • RedisCallback回调接口的使用。
  • Jedis的客户端API
  • RedisTemplate模板API

实践三:使用Spring缓存注解,完成Redis的缓存CRUD操作

具体步骤如下:

步骤01
        编写业务类UserServicelmplWithAnn类,使用缓存注解,完成User对象的缓存CRUD。

步骤02
        编写测试用例,访问UserServicelmplWithAnn类。观察在进行User对象的查询时,优先使用缓存数据,看看是否省去了数据库访问的时间。

本环节目标是掌握以下知识:

  • Spring缓存注解的使用。
  • Jedis的客户端API
  • Spring缓存注解的配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值