Nginx之简介

本文阅读 29 分钟
首页 代码,Java 正文

Nginx是一个高性能的HTTP和反向代理服务器。由俄罗斯人伊戈尔·赛索耶夫编写而成。目前有三个主要的社区版本:一个是Nginx官方的版本,一个是有淘宝网发起的Web服务器项目----Tengine,另一个是2011年有章亦春老师把LuaJIT VM嵌入Nginx中,实现了OpenResty这个高性能服务器。 其中,OpenResty目标是让web服务直接跑在Nginx服务内部,充分利用Nginx的非阻塞I/O模型,不仅对HTTP客户端请求,甚至对远程后端都进行一致的高性能响应。

高稳定性、丰富的的功能集、内存消耗少,并发能力强。

  • http服务器
  • 反向代理服务器
  • 负载均衡

正向代理和反向代理的用途都是代理服务中进行客户端请求的转发,但是区别很大。

正向代理

正向代理最大的特点是客户端非常明确要访问的服务器地址。 在正向代理服务器,客户端需要配置目标服务器信息,比如IP和端口,一般来说,正向代理服务器是一台和客户端网络连通的局域网内部的机器或者是可以打通两个隔离网络的双网卡机器。通过正向代理的方式,客户端的http请求可以转发到之前与客户端网络不通的其他不同的目标服务器。

反向代理

反向代理和正向代理相反,客户端不知道目标服务器的信息,代理服务器就像是原始的目标服务器,客户端不需要进行任何特别的设置。反向代理的最大特点是客户端不知道目标服务器地址。 客户端向反向代理服务器直接发送请求,接着反向代理将请求转发给目标服务器,并将目标服务器的响应结果按原路返回客户端。

正向代理和反向代理的使用场景

  • 正向代理的主要场景是客户端 由于网络不通等物理原因,需要通过正向代理服务器这种中间转发环节访问目标服务器。当然,也可以通过正向代理服务器对客户端某些详细信息进行一些伪装和改变。 换句话讲,正向代理是对客户端的伪装,隐藏了客户端 的IP、头部或者其他信息,服务器得到的是伪装过的客户端信息。
  • 发现代理的主要场景是服务端 服务提供方可以通过反向代理服务器轻松实现目标服务器的动态切换,实现多目标的负载均衡等。 换句话说,反向代理是对目标服务器的伪装,隐藏了目标服务器的IP、头部或者其他信息,客户端得到的是伪装过的目标服务器的信息。

Nginx对高并发的I/O的处理使用了Reactor事件驱动模型。Reactor模型的基本组件包含事件收集器、时间发送器、事件处理器三个基本单元,其核心思想是将所有要处理的I/O时间注册到一个中心I/O多路复用器上,同时主线程/进程阻塞在多路复用器上,一旦有I/O时间到来或者准备就绪,多路复用器返回并将事先注册的相应的I/O事件分发到对应的处理器上。 在Reactor模式中,三个基本单元的职责分别如下:

  • 事件收集器:负责收集Worker进程的各种I/O请求
  • 事件发送器:负责将I/O事件发送到事件处理器
  • 事件处理器:负责各种事件的响应工作

事件收集器将各个连接通道的I/O事件放入一个待处理事件列,通过事件发送器发送给对应的事件处理器处理。而事件收集器之所以能够同时管理上百万连接通道的事件,是基于操作系统提供的“多路IO复用”技术,常见的包括select、epoll两种模型。 正是因为Nginx使用了高性能的Reactor模式,因此是目前并发能力很高的Web服务器之一。当然,Nginx也解决了注明的网络读写的C10K问题。什么是C10K问题呢?其实就是网络服务再处理数以百万计的客户端连接时,往往出现效率低下甚至完全瘫痪,这类问题就被成为C10L问题

Nginx启动后会以daemon方式在后台运行,其后台进程有两类:一类称为Master进程(相当于管理进程);另一类为Worker进程(工作进程)。

Nginx的启动方式

  • 单进程启动:此时系统中仅有一个进程,该进程即充当Master管理进程,又充当Worker工作进程角色
  • 多进程启动:此时系统中只有一个Master管理进程, 至少有一个worker工作进程。 一般来说,单进程模式用于调试。在生产环境下一般会配置成为多进程模式,并且worker工作进程的数量和机器CPU核数配置一样。

Master管理进程的主要工作:

  • Master管理进程主要负责调度Worker工作进程,比如加载配置、启动工作进程、接收来自外界的信号、向各Worker进程发送信号、监控Worker进程的运行状态等。所以Nginx启动后,我们能够看到至少有两个Nginx进程。
  • Master负责创建监听套接口,交由Worker进程进行连接监听。

Worker进程的主要工作: Worker进程主要用来处理网络事件,当一个Worker进程在接收一条连接通道之后,就开始读取请求、解析请求、处理请求、处理完成产生数据后,再返回给客户端,最后断开连接通道。 各个Worker进程之间是对等且相互独立的,它们同等竞争来自客户端的请求,一个请求只能在一个Worker进程中处理。这都是典型的Reactor模型中Worker进程(或者线程)的职能。 如果启动了多个Worker进程,那么每个worker子进程独自尝试接收已连接的Socket监听通道,accept操作默认会上锁,优先使用操作系统的共享内存原子锁,如果操作系统不支持,就使用文件上锁。 经过配置,Worker进程的接收操作可以不使用锁,在多个进程同时接收时,当一个连接进来的时候多个工作进程同时被唤起,则会导致惊群问题。而在上锁的时候,只会有一个worker阻塞在accept上,其他的进程会因为不能获取锁而阻塞,所以上锁的场景不存在惊群问题

Nginx服务器被分解为多个模块,模块之间严格遵循“高内聚,低耦合”的原则,每个模块都聚焦于一个功能。高度模块化的设计是Nginx的架构基础。 什么事Nginx模块呢?在Nginx的实现中,一个模块包含一系列命令和这些命令相对应的处理函数。 Nginx的主要模块:

  • Core核心模块 核心模块是Nginx服务器正常运行必不可少的模块,提供错误日志记录、配置文件解析、Reactor事件驱动机制、进程管理等核心功能
  • 标准http模块 标准Http模块主要用于扩展标准的http协议解析相关的功能,比如端口配置、网页编码设置、http响应头设置等
  • 可选Http模块 可选http模块主要用于扩展标准的http功能,让Nginx能处理一些特殊的服务,比如Flash多媒体传输、网络传输压缩、安全协议ssl的支持等。
  • 邮件服务模块 邮件服务模块主要用于支持nginx的邮件服务,包括对POP3协议、IMAP协议和SMTP协议的支持。
  • 第三方模块 第三方模块是为了扩展Nginx服务器的功能,定制开发者自定义功能,比如Json支持、Lua支持等。

Nginx的非核心模块可以在编译时按需加入。

Nginx中HTTP请求的处理流程可以分为4步:

  • 读取解析请求行
  • 读取解析请求头
  • 多阶段处理,也就是执行handler处理器列表
  • 将结果返回给客户端 多阶段处理是Nginx的http处理流程中非常重要的一步。Nginx把请求处理划分为11个阶段:
  • post-read
  • server-rewrite
  • rewrite
  • find-config
  • post-rewrite
  • preaccess
  • access
  • post-access
  • try-files
  • content
  • log

一个Nginx配置文件包含若干配置项,每个配置项有配置指令和指令参数两部分组成。 Nginx配置文件中的配置指令如果包含空格,就需要用单引号或者双引号引起来。指令参数如果是由简单的字符窜构成的,简单配置项就需要以分号结束;指令参数如果是复杂的多行字符串,配置项就需要用花括号“{}”括起来。 Nginx指令的作用域配置块大致有五种,分别是:main,http,server,location,mail。为了方便我们对这些模块的介绍,我们先给出一个完整nginx的常用配置,然后针对这个配置文件来讲解各个模块的用法及作用。

  • main全局配置块 配置影响Nginx全局的指令,一般有运行nginx服务器的用户组、nginx进程PID存放路径、日志存放路径、配置文件引入、允许生成的worker进程数等。
  • events事件处理模块配置块 配置nginx服务器的IO多路复用模型、客户端的最大连接数限制等。Nginx支持多种IO多路复用模型,可以使用use指令在配置文件中设置IO读写模型。
  • http协议配置块 可以配置与http协议处理相关的参数,比如keepalive长连接、GZIP压缩参数、日志输出参数、mime-type参数、连接超时参数等。
  • server虚拟服务器配置快 配置虚拟主机的相关参数,如主机名称、端口等。一个http协议配置块中可以有多个server虚拟服务器配置块。
  • location路由规则块 配置客户端请求的路由配置规则以及请求过程中的处理流程。一个server虚拟服务器配置块中一般会有多个咯action路由规则块。
  • mail服务配置块 Nginx为email相关协议提供反向代理时,mail服务配置快负责配置一些相关的配置项。

events事件驱动配置

虚拟主机配置

location路由规则配置

location路由匹配主要分为精准匹配普通匹配正则匹配默认路径匹配

精准匹配

精准匹配的符号比较为“=”。 只有URI和精准匹配的模式字符串完全相同,精准匹配才通过。

普通匹配

普通匹配的符号标记为“^~”。 普通匹配属于字符串前缀匹配,具体来说:如果请求路径URI头部匹配到location的模式字符串,那么匹配成功。如果匹配到多个前缀,那么最长模式匹配优先。普通匹配也是Nginx默认的匹配类型。也就是说,类型符号“^~”可以省略。

正则匹配

正则匹配的类型按照类型符号的不同可以细分为4中:

  • “~”:标准正则匹配,区分字母大小写
  • “~*”:标准正则匹配,不区分字母大小写
  • “!~”:反向正则匹配,区分字母大小写
  • “!~*”:反向正则匹配,不区分字母大小写

正则匹配规则:如果配置文件中存在多个正则匹配location,那么他们之间的规则是顺序优先的,只要匹配到第一个正则类型的location,就停止后面的正则类型的location匹配。

默认根路径匹配

根路径的路径规则就是使用单个“/”符号。 表面上看,location / {}根路径匹配非常类似普通匹配,但实际上该规则自称一类,虽然只有唯一的一个路径,但是此类规则优先级是最低的。

四种匹配规则优先级

  • 类型之间的优先级:精确匹配>普通匹配>正则匹配>默认根路径匹配
  • 普通匹配同类型location之间的优先级为最长前缀优先。普通匹配的优先级与location在配置文件中所处的先后顺序无关,而与匹配到的前缀的长度有关。
  • 正则匹配同类型location之间的优先级为顺序优先。只要匹配到第一个正则规则的location,就停止后面的正则规则的匹配。正则匹配与location规则定义在配置文件中的先后顺序强相关。

反向代理和负载均衡配置

反向代理

反向代理通过proxy_pass指令来完成,proxy_pass指令格式的不同锁产生的代理效果也不同,大致可以分为三种:

  • 不带location前缀的代理 当proxy_pass后面的目标URI格式为:协议+ip:port+/根路径的格式时,表示最终的结果路径不会把location指令的URI前缀也给加上,这里称为不带前缀代理。 例如:
location / foo_no_perfix {
            proxy_pass   http://127.0.0.1:8888/;    #proxy_pass为反向代理指令,指向一个上游服务器。
        }

当我们在客户端发出请求http://192.168.233.1:80/foo_no_perfix /bar.html时,反向代理后URI其实为http://127.0.0.1:8888/bar.html,在结果URL中没有location配置指令的前缀foo_no_perfix 。

  • 带location前缀的代理 当proxy_pass后面的目标URI格式为:协议+ip:port的格式时,表示最终的结果路径会把location指令的URI前缀也给加上,这里称为带前缀代理。例如:
location / foo_perfix {
            proxy_pass   http://127.0.0.1:8888;    #proxy_pass为反向代理指令,指向一个上游服务器。
        }

当我们在客户端发出请求http://192.168.233.1:80/foo_no_perfix /bar.html时,反向代理后URI其实为http://127.0.0.1:8888/foo_perfix /bar.html,在结果URL中有location配置指令的前缀foo_perfix 。

  • 带部分URI路径的代理 如果proxy_pass 的路径参数中不止有ip和端口,还有部分目标URI的路径,那么最终的代理URL由两部分组成:第一部分为配置项中的目标URI前缀,第二部分为请求URI中去掉location中前缀的剩余部分。例如:
location / foo_uri_1 {
            proxy_pass   http://127.0.0.1:8888/aaa/;    #proxy_pass为反向代理指令,指向一个上游服务器。
        }

当我们在客户端发出请求http://192.168.233.1:80/foo_uri_1 /bar.html时,最终的结果URL为http://127.0.0.1:8888/aaa/bar.html。

location / foo_uri_2 {
            proxy_pass   http://127.0.0.1:8888/aaa-;    #proxy_pass为反向代理指令,指向一个上游服务器。
        }

当我们在客户端发出请求http://192.168.233.1:80/foo_uri_2 /bar.html时,最终的结果URL为http://127.0.0.1:8888/aaa-bar.html。 这里有个问题需要注意:仅仅使用proxy_pass指令进行反向代理之后,会丢失很多原始的请求信息,例如:客户端的ip地址等,对于目标服务器来说,客户端的本质已经发生了变化,因此后端的目标服务器无法直接拿到客户端的ip地址等信息。要解决这个问题我们可以使用proxy_set_header指令。使用如下:

location / foo_uri_2 {
            proxy_set_header   X-real-ip   $remote_addr ;
            proxy_pass   http://127.0.0.1:8888/aaa-;    
        }

proxy_set_header X-real-ip $remote_addr :此设置的意思是将客户端的真实ip保存到名称为“X-real-ip”的请求头中,java段使用request.getHeader(“X-real-ip”),$remote_addr是nginx的内置参数,用于获取客户端的真是ip地址。 在整个请求处理的链条上可能不仅一次的反向代理,可能会经过N此反向代理。为了获取整理代理转发记录,也可以用proxy_set_header完成。

location / foo_uri_2 {
            proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
            proxy_set_header   X-real-ip   $remote_addr ;    #客户端ip
            proxy_set_header   Host   $host ;    #当前的目标主机
            proxy_redirect off;
            proxy_pass   http://127.0.0.1:8888/aaa-;  
        }

proxy_redirect指令的作用是修改从上游被代理服务器传来的应答头中的Location和Refresh字段,尤其是上游服务器返回的响应码是重定向或刷新请求(如响应码301或302)时,proxy_redirect可以重设HTTP头部的location或refresh字段值。off参数表示禁止所有的proxy_redirect指令。

负载均衡

反向代理是负载均衡实现的基础之一。下面给出一个简单的负载均衡的实现来依次进行讲解。

server {
        listen       80;    #配置监听端口
        server_name  admin.crazydemo.com;    #虚拟机名称
        
        upstream balanceName{
        zone    gateway    64k;
        server "192.18.1.1:8080"    weight=2    max_conns=500;
        server "192.18.1.2:8080"     fail_timeout=20s    max_fails=2;    #没有配置weight时,默认为1
        server "192.18.1.3:8080"    down;
        server "192.18.1.4:8080"    backup;
        }
        location / {
            proxy_pass   http://balanceName;    
        }
    }

内部server指令的语法如下:server address [parameters],此内嵌的server指令用于定义上游服务器的地址和其他可选参数,它的地址可以指定为域名或ip地址带有可选端口,如果未指定端口,就使用端口80。 内嵌的server指令的可选参数大致有:

  • weight=number:设置上游服务器的权重
  • max_conns=number设置上游服务器的最大连接数
  • backup:标识该server是备份上游节点 当普通的上游服务(非backup)不可用时,请求将被转发到备份的上游节点;当普通的上游服务(非backup)可用时,备份的上游节点不接受处理请求。
  • down:标识该上游服务器为不可用或永久下线的状态
  • max_fails=number:最大错误次数 如果上游服务器不可访问了,如何判断呢?max_fails参数就是其中之一,该参数表示请求转发最多失败number此就判定改server为不可用。max_fails参数默认为1,表示转发失败1次,改server即不可用。如果此参数设置为0,就会禁用不可用的判断,一直不断的尝试连接后端server。
  • fail_timeout=time:失败测试的时间长度。 此参数一般与max_fails协同使用,指的是在fail_timeout时间范围内最多尝试max_fails次,就判定改server不可用。fail_timeout参数默认为10秒。

server指令在进行max_conns连接数配置时,Nginx内部会涉及共享内存区域的使用,配置共享内存区域的指令为zone。zone指令的语法如下: zone name [size]; 其中name参数设置共享内存区的名称,size可选参数用于设置共享内存区域的大小。如果配置了upstream的共享内存区域,那么其运行时状态(包括最大连接数)在所有的Worder工作进程之间是共享的。在name相同的情况下,不同的upstream组将共享同一个区,这种情况下,size参数的大小只需要设置一次。 upstream的负载分配方式

  • 加权轮询 默认情况下,upstream使用加权轮询,默认的权重weight值为1,并且各上游服务器weight值相同,表示每个请求按到达的先后顺序逐一分配到不同的上游服务器,如果某个上游服务器宕机,就自动剔除。
  • hash指令 基于hash函数值进行负载均衡,hash函数的key可以包含文本、变量或二者的组合。hash函数负载是一个独立的指令,指令的格式如下: hash key [consistent]; 注意,如果upstream组中摘除掉一个server,就会导致hash值重新计算,即原来的大多数key可能寻址到不同的server上。若配置有consistent参数,则hash一致性将选择Ketama算法。这个算法的优势是,如果有server从upstream组中被踢出,那么只有少数的key会重新映射到其他额server上,即大多数可以不受server摘除的影响,还走原来的server。这对提高缓存server命中率有很大的帮助。例如:
upstream balanceName{
        hash    $request_uri    consistent;
        server "192.18.1.1:8080"    weight=2    max_conns=500;
        server "192.18.1.2:8080"     fail_timeout=20s    max_fails=2;    #没有配置weight时,默认为1
        server "192.18.1.3:8080"    down;
        server "192.18.1.4:8080"    backup;
        }
  • ip_hash指令 基于客户端ip的hash值进行负载均衡,这样这个客户端固定访问同一个后端服务器,可以解决类似session不能跨服务器的问题。如果上游server不可用,就需要手工摘除或者配置down参数。
upstream balanceName{
        ip_hash;
        server "192.18.1.1:8080"    weight=2    max_conns=500;
        server "192.18.1.2:8080"     fail_timeout=20s    max_fails=2;    #没有配置weight时,默认为1
        server "192.18.1.3:8080"    down;
        server "192.18.1.4:8080"    backup;
        }

一个完整的nginx配置如下:

#主配置开始
#user  nobody;    配置用户或者组,默认为nobody nobody。
worker_processes  1;                #worker进程个数,默认是1    最好配置成和内核数量一致的worker进程数,这样在处理请求时效率最高
worker_cpu_affinity   1000     0100    0010   0001;                #将worker进程和CPU内核绑定

#error_log  logs/error.log    debug;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;    #设置日志路径和日志级别。这个设置可以放入全局块、http块、server块。日志级别类型为:debug | info | notice | warn | error | crit | alert | emerg  关闭日志的唯一方式:/dev/null
debug_connection    10.224.66.14:14  #仅仅来自这个IP的地址的请求才会输出debug级别的日志,其他的请求仍然沿用error_log中配置的日志级别  注意:使用这个参数的前提是在执行configure时已经加入了--with-debug参数    

#pid        logs/nginx.pid;    #指定nginx的master进程ID的pid文件存放路径
#主配置结束

#事件配置开始
events {
    accept_mutex on;    #配置各个worker进程是否通过互斥锁有序接收新的连接请求,开启后可以防止惊群现象发生,默认为on
    lock_file      logs/nginx.lock     #accept锁可能需要这个lock文件,如果accept锁关闭这个文件就完全不生效,如果打开并且由于编译程序,操作系统架构等因素导致Nginx不支持原子锁,这时才会用文件锁实现accept锁
    worker_connections  1024;    #每个worker进程可以同时处理的最大连接数,默认为512
    use epoll;   #配置IO多路复用模型,常用的有select、epoll两种,一般选用epoll
}
#事件配置开始

#http配置开始
http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '    #日志的输出格式,main为日志格式名称
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;    #Nginx将客户端的访问日志信息记录到执行的日志文件中,用于后期分析用户的浏览行为,其中main为使用的日志输出格式

    sendfile        on;    #允许sendfile方式传输文件,默认为off,可以在http块,server块,location块
    #tcp_nopush     on;

    #keepalive_timeout  65;    #配置长连接有效时长,0表示禁止长连接,默认为75秒
    #keepalive_requsts  200;    #配置长连接的一条连接允许的最大请求数,默认为100
    #send_timeout 100;    #配置向客户端发送响应报文的超时限制,time参数用于设置Nginx向客户端发送响应报文的超时限制,此处时长是指两次想客户单写操作之间的间隔时长,并非整个响应过程的传输时长


    #gzip  on;

    server {
        listen       80;    #配置监听端口
        server_name  admin.crazydemo.com;    #虚拟机名称
        #charset utf-8;    
        #access_log  logs/host.access.log  main;

        #表示在请求URI匹配到"/"根路由规则时,首先Nginx会在html目录下查找index.htmlwenjian ,如果没有找到,就查找index.htm文件,将找到的文件内容返回给客户端
        location / {
            root   html;
            index  index.html index.htm;
        }
        #表示在请求URI匹配到"/"根路由规则时,将请求路由到一个访问很频繁的上游服务,例如网关服务:http://127.0.0.1:8888/,这里也是nginx反向代理的应用
        location / {
            proxy_pass   http://127.0.0.1:8888/;    #proxy_pass为反向代理指令,指向一个上游服务器。需要注意proxy_pass指令根据所写的格式不同分为:不带前缀代理、带前缀代理和带部分URI路径的代理,后面会详细介绍
        }
        
        #nginx负载均衡应用建立在反向代理的基础之上,其实就是将proxy_pass指令后的参数指向我们定义的好的上游服务器组名称,也就是upstream的名称。后面会详细介绍负载均衡的规则以及upstream块的使用。
        upstream balanceName{
        server "192.18.1.1:8080";
        server "192.18.1.2:8080";
        server "192.18.1.3:8080";
        server "192.18.1.4:8080";
        }
        location / {
            proxy_pass   http://balanceName;    #proxy_pass为反向代理指令,指向一个上游服务器。需要注意proxy_pass指令根据所写的格式不同分为:不带前缀代理、带前缀代理和带部分URI路径的代理,后面会详细介绍
        }
        
        #静态文件路由规则。有两种配置方式:目录匹配(前缀匹配)和后缀匹配(正则匹配)。
        #第一种静态文件路由配置:前缀匹配,例如:请求http://127.0.0.1:6666/static/ing/1.png,将匹配到root指令/www/resources/static/下对应的某个文件(/www/resources/static/ing/1.png),当然root /www/resources/static/指令是可以去掉的
        root /www/resources/static/
        location ^~ /static {
            root /www/resources/;
        }
        #第二种静态文件路由配置:后缀匹配。例如
        location ~*\.(gif|jpg|jpeg|png|css|js|ico)$ {
            root D:/babaike;
        }
        

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #location ~ /\.ht {
        #    deny  all;    #拒绝所有服务器访问
        #    allow 192.168.1.5    #只允许192.168.1.5服务器访问
        #}
        
        #error_page  404              /404.html;    #错误页面配置
        # 将服务器错误页面重定向到静态页面 /50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    
    server {
        listen       80;    #配置监听端口
        server_name  file.crazydemo.com;    #虚拟机名称
    
    }
    
    server {
        listen       80 default;    #配置监听端口
        server_name  crazydemo.com *.crazydemo.com;    #如果没有前缀,这就是默认访问的虚拟机名称
    }
}
#http配置开始结束

Nginx官网

本文为互联网自动采集或经作者授权后发布,本文观点不代表立场,若侵权下架请联系我们删帖处理!文章出自:https://blog.csdn.net/qq_38571892/article/details/119455515
-- 展开阅读全文 --
Web安全—逻辑越权漏洞(BAC)
« 上一篇 03-13
Redis底层数据结构--简单动态字符串
下一篇 » 04-10

发表评论

成为第一个评论的人

热门文章

标签TAG

最近回复