我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java如何手写Redis服务端

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java如何手写Redis服务端

小编给大家分享一下Java如何手写Redis服务端,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

一,redis通讯与Netty

1,tcp

连到Redis服务器的客户端建立了一个到6379端口的TCP连接。

虽然RESP在技术上不特定于TCP,但是在Redis的上下文中,该协议仅用于TCP连接(或类似的面向流的连接,如unix套接字)。

使用netty作为通讯框架。

2,协议

Redis客户端和服务器端通信使用名为 RESP (REdis Serialization Protocol) 的协议。虽然这个协议是专门为Redis设计的,它也可以用在其它 client-server 通信模式的软件上。 RESP 协议在Redis1.2被引入,直到Redis2.0才成为和Redis服务器通信的标准。这个协议需要在你的Redis客户端实现。

RESP 是一个支持多种数据类型的序列化协议:简单字符串(Simple Strings),错误( Errors),整型( Integers), 大容量字符串(Bulk Strings)和数组(Arrays)。

RESP在Redis中作为一个请求-响应协议以如下方式使用:

客户端以大容量字符串RESP数组的方式发送命令给服务器端。 服务器端根据命令的具体实现返回某一种RESP数据类型。 在 RESP 中,数据的类型依赖于首字节:

单行字符串(Simple Strings): 响应的首字节是 "+" 错误(Errors): 响应的首字节是 "-" 整型(Integers): 响应的首字节是 ":" 多行字符串(Bulk Strings): 响应的首字节是"$" 数组(Arrays): 响应的首字节是 "*" 另外,RESP可以使用大容量字符串或者数组类型的特殊变量表示空值,下面会具体解释。RESP协议的不同部分总是以 "\r\n" (CRLF) 结束。 字符串 "foobar" 编码如下:

"$6\r\nfoobar\r\n"

实际redis命令是什么样的,比如 SET lhjljh lhjkjhkh

*3\r\n$3\r\nSET\r\n$6\r\nlhjljh\r\n$8\r\nlhjkjhkh

3,编解码

由于RESP天然是面向处理命令的,所以没办法直接把redis消息像grpc或者dubbo那样直接序列化和反序列化消息。并且每个内容限定了长度,很适合做成及时序列化、零拷贝,直接针对输入流做反序列化和序列化,这一点与Protostuff序列化协议的设计很类似。 所以序列化直接将服务端接收的流直接转成值。

Java如何手写Redis服务端

编解码的实体类直接加入redis server 的处理某一个长连接tcp客户端的管道上。

Java如何手写Redis服务端

4,命令处理

将消息解码成RESP,还需要将RESP转为Command对象,这里因为是java语言,方法与类绑定,编写上和理解上会更加容易。但是会增加一些开销。

Java如何手写Redis服务端

二,redis 的数据结构

1,底层主结构

底层主树使用跳表ConcurrentSkipListMap实现,没用hash类map的原因是服务端是集群后,客户端可能使用hash路由,会导致服务端严重的hash冲突,性能大打折扣

Java如何手写Redis服务端

key为封装的“String”,重写了equals方法避免相同的key但是在jvm中指针不同

Java如何手写Redis服务端

value是一个接口,实现类是redis的五大基本类型,所有数据类型都包含超时时间

Java如何手写Redis服务端

2,key

用封装的值做value的原因是方便统一管理

Java如何手写Redis服务端

3,list

底层使用LinkedList的原因是LinkedList实现了多种接口,实现各种命令直接调用其现成实现的方法即可

Java如何手写Redis服务端

Java如何手写Redis服务端

4,set

底层使用HashSet,redis里的set没有多特殊

Java如何手写Redis服务端

5,hash

底层使用HashMap,这里和开头说的HashMap不冲突。为什么不用跳表?压缩列表很巧妙,大抵的意思就是将通信收到的数组直接填充到list中,将list直接按照次序直接当map使用,主要是0拷贝的思想,无需创建新资源,性能极高,但注意压缩列表与压缩无关。

Java如何手写Redis服务端

6,zset

首先需要封装一个带有值和分值的对象

Java如何手写Redis服务端

再用TreeMap重写compare方法即可,使用TreeMap原因是他天然有良好的排序功能,很多hash一致路由的算法都用的TreeMap二开。

Java如何手写Redis服务端

三,redis AOF 持久化

1,aof线程与tcp线程解耦,即写缓冲

再解析redis命令时,将redis写命令添加到写aof日志的队列中

Java如何手写Redis服务端

这里自己封装了一个堵塞队列,单线程吞吐量可以达到3000W /s是LinkedBlockingQueue的6到10倍,完全可以胜任此场景

Java如何手写Redis服务端

Java如何手写Redis服务端

RingBlockingQueue吞吐量非常高的原因是使用了内存连续页的机制。

Java如何手写Redis服务端

2,aof持久化协议

aof协议一句话概括就是将写命令,追加到日志中,开始时将命令读取,当作收到网络的命令执行即可。由于协议过于简单,这里就不贴链接了。 aof之日格式如下图:

Java如何手写Redis服务端

3,aof的加载与存储实现

这里读写内存都是用的内存文件映射,好处是读写性能好,坏处是可能会出现内存泄漏,调试期间比较麻烦。

Java如何手写Redis服务端

4,内存文件映射与面向对象

这里存储和加载aof文件的代码都是面向过程的,看起来非常复杂。实际上之前是按照面向对象写的,封装成了行对象,调用落盘符和拾起方法就可以写入和读取aof中的命令,但是TPS仅为10w/s,后来权衡后改为面向过程,吞吐量提升到了100W的TPS以上。

四,redis 的集群特性

1,主从

这里很容易联想到mysql的只从,很多场景下会使用基于mysql主从的读写分离,或者zk的主从。 但实际上redis的主从是不保证一致性的,个人认为redist的主从主要考虑的是cap的分布式容错性。 因为redis主从不保证一致性,所以使用redis读写分离,可能造成一些不一致的问题,写写是一致的,但是读是不一致的,可以根据项目需要做取舍。

2,主从复制

redis的主从复制这里作者没看懂(可能也是一致性上有坑没动力去看),所以没写出来。

3,分片集群

redis集群主要分为几个唯独: 主从、分区集群、代理。 一般在redis客户端的视角下,主要是分区集群,根据发送给redis的key做hash、md5等操作,取一个所有客户端的共识值,将key和value发送,也就是客户端路由分布式软件的集群实现方式京东的redis集群设计到redis具体一个分片。

五,redis 的压测与调优

1,aof内存泄漏

开启aof压测发现出现了内存泄漏,后来发现是频繁新建内存池而造成的,所以将内存池池化,即aof对象中仅存在一个bytebuff内存池。

2,内存复用提升性能

这里编解码没有单独开辟byte数据接收bytebuff的数据进行编解码,编解码直接读取bytebuff进行编解码,没有出现内存拷贝,唯独新建了BytesWrapper对象,但存储的数据都是使用BytesWrapper对象,对内存新建/销毁的开销很少。

3,0.05%消息延迟超200ms排查

下图为c语言版的redis压测数据:

Java如何手写Redis服务端

下图为java语言版的redis压测数据:

Java如何手写Redis服务端

4,性能表现

redis原版的性能大概是E5系列CPU 4-5w左右,上图中是使用amd芯片测试的数据。 使用redis自带的压测工具,维持100个客户端连接,java版性能是c语言原版性能的75-90%左右,性能依然强悍。

看完了这篇文章,相信你对“Java如何手写Redis服务端”有了一定的了解,如果想了解更多相关知识,欢迎关注编程网行业资讯频道,感谢各位的阅读!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java如何手写Redis服务端

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java如何手写Redis服务端

小编给大家分享一下Java如何手写Redis服务端,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!一,redis通讯与Netty1,tcp连到Redis服务器的客户端建立了一个到6379端口的TCP连接。虽然RESP在技术上
2023-06-22

Java如何把数据写入redis

本文介绍了使用JavaAPI与Redis交互的方法,重点讲解了将数据写入哈希表、列表、集合和有序集合。它强调了JedisAPI的使用,提供了详细的代码示例用于执行写入操作。此外,还讨论了其他写入操作、批量写入以及连接管理最佳实践。
Java如何把数据写入redis
2024-04-02

Java如何使用redis写登录

使用Redis和Java实现登录。连接Redis服务器,创建用户和验证凭据。处理会话并获取用户详情。还可以使用令牌验证身份,生成、验证并将其存储在Redis中。RedisSessions库简化了会话管理。最佳实践包括使用强密码、哈希密码、适当的会话管理、清理过期的会话和加密连接。
Java如何使用redis写登录
2024-04-02

如何用java编写一个redis

本文详细介绍了如何使用Java编写Redis客户端。它涵盖了Redis简介、Java编写Redis客户端的依赖库以及使用Jedis、Lettuce和Redisson这三个库编写客户端的示例。文章还提到了连接池的使用、异常处理、序列化和反序列化以及优化数据结构和命令等其他注意事项。
如何用java编写一个redis
2024-04-02

java秒杀商品如何写进redis

本指南详细介绍了将秒杀商品写入Redis的方法。通过设置Redis数据结构、设置过期时间和初始化库存,可以实现商品的高并发快速访问。秒杀过程中,系统实时扣减库存,并提供成功/失败响应。活动结束后,需要清理Redis中的商品信息。文中还提供了示例代码和优化建议。
java秒杀商品如何写进redis
2024-04-02

java如何实现redis读写分离

Java中实现Redis读写分离涉及创建主服务器、从服务器和管理连接池。主服务器处理写入操作,而从服务器复制主服务器数据进行读取。Java客户端使用Jedis连接到主服务器和从服务器,并使用连接池管理连接。故障转移机制确保主服务器故障时从服务器自动提升为主服务器。需要注意网络连接稳定性、复制状态、资源分配和负载均衡策略。其他工具(如RedisSentinel或RedisCluster)可实现自动故障转移和分片。
java如何实现redis读写分离
2024-04-02

Java中Socket如何实现Redis客户端

小编给大家分享一下Java中Socket如何实现Redis客户端,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!Redis是最常见的缓存服务中间件,在java开发中,一般使用 jedis 来实现。Redis的命令协议:$参数
2023-06-15

如何操作云服务器手机端

如果您是使用云服务器进行移动端的云存储,那么您可以使用以下方法操作手机端:下载并安装手机操作系统。在您的智能手机上安装相应的操作系统以及适配的云服务器软件,可以在各个应用市场或者应用商店中搜索“云服务器”并下载安装。登录服务器账号。在登录服务器账号的页面中输入您的个人账户信息,包括您的密码和安全问题。创建云存储文件夹。在云存储文件夹中创建一个新的云存储文件夹,并为该文件夹设置密码。导入云服务器文件。在手...
2023-10-27

java WebSocket 服务端如何实现

这篇文章给大家分享的是有关java WebSocket 服务端如何实现的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1.什么是WebSocket  WebSocket协议是基于TCP的一种新的网络协议。它实现了浏
2023-06-29

云服务器如何防止ddos攻击手机端端口

攻击者可以通过使用DDoS(分布式拒绝服务)攻击、缓冲区溢出攻击、DNS劫持等方式来攻击云服务器。这些攻击会导致云服务器资源被耗尽,无法提供足够的服务。为了防止DDoS攻击,我们可以采取以下措施:使用高性能的云服务器高性能的云服务器可以提供更快的计算速度和更高的存储容量。因此,我们应该选择使用高性能的云服务器,并确保它
云服务器如何防止ddos攻击手机端端口
2023-10-28

手机如何登录阿里云服务器端

如果您使用的是阿里云手机,以下是登录阿里云服务器端的方法:点击手机桌面上的“设置”图标。进入设置页面后,点击“账户与安全”选项。在“账户与安全”页面中,点击“登录”选项。在弹出的登录对话框中,输入您的账号和密码,然后点击“登录”按钮即可登录阿里云手机。请注意,登录阿里云服务器需要使用阿里云账号。如果您没有阿里云账号,可以先下载一个阿里云账号,然后登录您的阿里云账号。如果您想在手机上使用阿
2023-10-27

云服务器如何重置密码手机端

首先,让我们来了解一下云服务器的基本知识。云服务器是一种基于互联网的服务器,它通过网络连接到各个设备上,以便用户可以访问和使用它们。在云服务器上,用户可以通过Web浏览器、移动设备或其他应用程序访问它们。云服务器可以通过控制面板或管理控制台来管理和配置它们。控制面板允许用户轻松地管理云服务器的设置和参数,而管理控制台则
云服务器如何重置密码手机端
2023-10-28

如何用云服务器玩游戏手机端

用云服务器玩游戏手机端可以节省大量的带宽和存储空间,因为它们使用的是服务器提供的云存储服务。以下是一些步骤,您可以在游戏平台使用云服务器玩游戏。选择一个合适的云服务器品牌和配置:您可以选择云服务器提供商的品牌和配置,也可以根据自己的需求进行选择。一些比较知名的云服务器提供商包括:阿里云、腾讯云、UCloud等。购买和安装云服务器:在购买云服务器之前,建议您先了解其提供的功能和特点。您可以咨
2023-10-26

java如何读取服务器端文件

Java读取服务器端文件在Java中,可以通过多种方法读取服务器端文件。本文介绍了最常用的方法:文件输入流:简单易用,适用于小型文件。缓冲文件输入流:性能更高,适用于大型文件。对象输入流:可读取文件中存储的对象。选择方法取决于需求:小型文件用文件输入流,大型文件用缓冲文件输入流,读取对象用对象输入流。此外,文中还提供了注意事项,如使用try-with-resources语句管理流、处理文件结束符和流式处理大型文件。
java如何读取服务器端文件
2024-04-11

java如何读取服务器端文件

要读取服务器端的文件,可以使用Java中的java.net包中的类来建立与服务器的连接,并通过输入流来读取文件内容。以下是一个简单的示例:import java.io.BufferedReader;import java.io.IOEx
java如何读取服务器端文件
2024-04-09

手机端阿里云如何打开服务器

本文主要介绍如何在手机端使用阿里云打开服务器。首先,需要了解阿里云服务器的基本概念和操作方法,然后在手机上安装阿里云手机客户端,最后按照提示操作,即可在手机端打开阿里云服务器。正文:阿里云手机客户端是阿里云提供的一款用于管理阿里云服务器的手机应用,用户可以在手机上通过这款应用,轻松管理自己的阿里云服务器,无需电脑
手机端阿里云如何打开服务器
2023-10-30

手机如何登陆阿里云服务器端

如果您使用的是阿里云提供的服务器,以下是在手机上登录阿里云服务器端的步骤:打开Android手机应用商店,在其中搜索“阿里云服务器”并下载安装阿里云应用;打开Chrome浏览器,在页面顶部导航栏中找到并进入“开发者工具”;在“开发者工具”中,点击“登录”按钮,输入您的阿里云账号和密码,然后点击“登录”按钮;进入阿里云账户登录界面,输入您的账户信息和安全信息,然后点击“登录&r
2023-10-26

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录