• GO语言泛型编程实践

    紧接着上次说到的RDB文件解析功能,数据解析步骤完成后,下一个问题就是如何保存解析出来的数据,Redis有多种数据类型,string、hash、list、zset、set,一开始想到的方案是为每一种数据定义一种数据结构,根据不同的数据类型,将数据保存到不同的数据结构,但是这样的做法带来了比较多的冗余代码,以string和hash为例,一开始的代码是这样的:

    Read more...
  • [从0到1编写服务器]TCP连接建立与断开状态变化

    上篇介绍了socket编程的准备知识,是不是有一种很想马上就开始了解网络编程,甚至开始写点代码的感觉,别着急,网络编程中还有一个比较重要的概念是TCP/IP,中文名称叫网络传输协议,本质上,TCP/IP是一种协议,同时也是网络编程中最重要的协议之一。TCP/IP涉及到的内容实在太多,无奈笔者才疏学浅,无法把整个TCP/IP介绍给大家,这篇文章的目的主要是基于上一篇文章的前提下,介绍TCP连接三次握手和断开连接四次挥手究竟做了什么?socket的状态有哪些?在各个API执行的过程中,socket的状态是怎么变化的?希望通过这篇文章,能让大家对在TCP连接建立与断开过程中,socket的整个状态变化流程有更深入的了解。

    几个术语

    SYN : 同步序列编号,Synchronize Sequence Numbers,仅在三次握手建立TCP连接时有效。表示一个新的TCP连接请求。

    ACK : 确认编号,Acknowledgement Number,对TCP请求的确认标志,同时提示对端系统已经成功接收所有数据。

    FIN : 结束标志,FINISH,用来结束一个TCP会话,但对应端口仍处于开放状态,准备接收后续数据。

    Read more...
  • [从0到1编写服务器]准备知识

    前言

    在互联网发达的时代里,我们的开发过程中,很多场景几乎都需要跟网络打交道,数据库连接、redis连接、nginx转发、RPC服务等等,这个服务器软件的底层实现本质都是网络编程,这也是为什么很多公司在面试的时候都会问到计算机网络。诚然,在正常开发的过程下,几乎不会去自己编写一个完整的服务器,但是,在开发中理解一些概念性的知识却非常有用,甚至在排查一下稀奇古怪的网络错误的时候,TCP/IP协议可以发挥巨大的用处。如果在排查奇怪的问题时,你把学到的网络知识发挥了用途,那么你在公司的前景就不用多说了,而且,作为一个有追求的程序员,不能仅仅满足于业务开发,底层的计算机原理也要经常巩固。毕竟基础知识真的非常重要。

    Read more...
  • [深入理解Redis]读取RDB文件

    最近在做一个解析rdb文件的功能,途中遇到了一些问题,也解决了一些问题。具体为什么要做这件事情之后再详谈,本次主要想聊聊遇到的开始处理文件时遇到的第一个难题:理解RDB文件的协议、如何读取二进制文件。

    RDB文件

    [Redis源码阅读]redis持久化 文章介绍过,Redis的持久化是通过RDB和AOF实现的。Redis的RDB文件是二进制格式的文件,从这个方面再次体现了Redis是基于内存的缓存数据库,不管对于存储到硬盘还是恢复数据都十分快捷。Redis有多种数据类型:string、list、hash、set、zset,不同数据类型占用的内存大小是不一样的,解析出自然语言可以识别的数据就需要使用不同的方法,保存到文件的时候也需要一些协议或者规则。这有点类似于编程语言里面的数据类型,不同的数据类型占用的字节大小不一致,但是保存到计算机都是二进制的编码,就看是读取多少个字节,以怎样的方式解读。

    Read more...
  • [Redis源码阅读]实现一个redis命令--nonzerodecr

    上篇文章介绍了命令的执行流程,对redis如何执行命令也有了初步的了解,通过实现一个redis命令来再次加深印象。

    笔者平时主要语言是PHP,有些功能PHP无法满足就会用到PHP的扩展,比如swoole。因此,就想到redis可不可以以做扩展?为了满足一些特殊的需求,可不可以为redis开发一个命令?

    前期准备

    因为redis是用C开发的,为了能开发redis命令,首先也是必须的是,你要懂一点C语言基础,另一个就是,需要了解一下redis命令是如何执行的,知道redis执行命令大概的流程,最简单的一个流程描述就是:

    读取命令->解析命令->调用命令函数->返回执行结果
    

    或者再读一次上篇文章

    我们要做的就是,确保redis能解析到新增的命令,能根据输入的命令找到对应的方法并执行。

    Read more...
  • [Redis源码阅读]当你输入get/set命令的时候,redis做了什么

    上一篇文章介绍了redis-server的启动过程,服务端启动之后,就启动事件循环机制监听新事件的到来,此时不同的客户端就可以通过发送指令的方式请求server并得到处理结果的回复。在开发过程中,用到最多的就是get和set命令,那么,当我们输入get/set命令时,redis做了什么呢?

    redis-cli启动

    了解命令是如何使用之前,先了解下redis-client启动时做了什么。redis客户端有多种实现,不同的语言也有自己的实现,在这里可以看到各种版本:redis版本,平常调试过程中比较常用的是redis-client,即命令行的形式,redis-client的主要实现代码在redis-cli.hredis-cli.c。redis-client的启动入口是在main函数,阅读代码可以看到是先给config设置属性,然后判断客户端使用哪种模式启动,启动模式有:Latency、Latency分布式、从库、获取RDB、查找大key、管道、Stat、Scan、LRU、Intrinsic Latency、交互模式。我们用的命令行就是交互模式。

    Read more...
  • [Redis源码阅读]当你启动Redis的时候,Redis做了什么

    直奔主题,当启动Redis的时候,Redis执行了哪些操作?

    假设Redis安装在了/usr/local/目录下,那么启动Redis是通过执行/usr/local/bin/redis-server -c xxx.conf的方式执行。 redis-server是一个通过编译server.c文件生成的程序,因此想了解redis是怎么启动的,应该从server.c/main函数入手。

    具体代码可见:server.c

    Read more...
  • [Redis源码阅读]redis持久化

    作为web开发的一员,相信大家的面试经历里少不了会遇到这个问题:redis是怎么做持久化的?

    不急着给出答案,先停下来思考一下,然后再看看下面的介绍。希望看了这边文章后,你能够回答这个问题。

    为什么需要持久化?

    由于Redis是一种内存型数据库,即服务器在运行时,系统为其分配了一部分内存存储数据,一旦服务器挂了,或者突然宕机了,那么数据库里面的数据将会丢失,为了使服务器即使突然关机也能保存数据,必须通过持久化的方式将数据从内存保存到磁盘中。

    对于进行持久化的程序来说,数据从程序写到计算机的磁盘的流程如下:

    1、客户端发送一个写指令给数据库(此时数据在客户端的内存)

    Read more...
  • [Redis源码阅读]redis对象

    结构定义

    在redis中,对象的数据结构定义如下:

    ​typedef struct redisObject {
        ​unsigned type:4;
        ​unsgined encoding:4;
        ​unsigned lru:LRU_BITS;
        ​int refcount;
        ​void *ptr;
    ​}
    

    结构定义中的type:4encoding:4这种定义方式称为位段类型

    使用位段类型的好处就是避免浪费内存,如果使用unsigned int type定义type字段,需要4个字节,而使用unsigned type:4,只需要4个位段就足够了。

    Read more...
  • [Redis源码阅读]dict字典的实现

    dict的用途

    dict是一种用于保存键值对的抽象数据结构,在redis中使用非常广泛,比如数据库、哈希结构的底层。

    当执行下面这个命令:

    > set msg "hello"
    

    以及使用哈希结构,如:

    > hset people name "hoohack"
    

    都会使用到dict作为底层数据结构的实现。

    Read more...