使用源码包编译安装Nginx

  • Nginx 代码提供了两种独立的下载分支一一开发版与稳定版。开发分支是个正处于 积极开发状态的版本。在这个版本中,会有一些新功能被集成到其中,在稳定版中是找不到这些功能的。当发布 个“开发”版时,它会经历同样的 QA 和作为稳定版的一组类似 功能测试。因此,无论哪 个分支都可以用于生产环境中。两者主要的不同,在于对第 方模块的支持。在开发版中,内部的 API 可能会发生改变,而稳定版则保持不变。因此, 为了与第 方模块向下兼容,在稳定版中第三方模块都可以有效使用

一、安装前的准备

  • 安装Nginx前需要准备一下几样东西。其中gcc是必须要安装的,其他三个库根据自己的需求安装,如果用到了就安装,用不到就不需要安装

①GCC编译器

  • GCC是必需的编译工具,一般系统自带,如果没有可以使用下面的方式安装
sudo apt-get install gcc

②PCRE库

  • PCRE(Perl Compatible Regular Expressions,Perl兼容正则表达式)是由Philip Hazel开发的函数库,目前为很多软件所使用,该库支持正则表达式。它由RegEx演化而来,实际上, Perl正则表达式也是源自于Henry Spencer写的RegE
  • 如果我们在配置文件nginx.conf里使用了正则表达式,那么在编译Nginx时就必须把PCRE库编译进Nginx,因为Nginx的HTTP模块要靠它来解析正则表达式
  • 其安装方式如下:
    • pcre是直接使用的库
    • pcre-devel是使用PCRE做二次开发时所需要的开发库,包括头文件等,这也是编译Nginx所必须使用的
sudo apt-get install pcre pcre-devel

③zlib库

  • zlib库用于对HTTP包的内容做gzip格式的压缩,如果我们在nginx.conf里配置了gzip on, 并指定对于某些类型(content-type)的HTTP响应使用gzip来进行压缩以减少网络传输量,那么,在编译时就必须把zlib编译进Nginx
  • 其安装方式如下:
    • zlib是直接使用的库
    • zlib-devel是二次开发所需要的库
sudo apt-get install zlib zlib-devel

④OpenSSL开发库

  • 如果我们的服务器不只是要支持HTTP,还需要在更安全的SSL协议上传输HTTP,那么就需要拥有OpenSSL了。另外,如果我们想使用MD5、SHA1等散列函数,那么也需要安装 它
  • 其安装方式如下:
    • openssl是直接使用的库
    • openssl-devel是二次开发所需要的库
sudo apt-get install openssl openssl-devel

二、编译安装

①准备好要使用的源码包

  • 在家目录下建立一个build目录(目录名自己随意取),用来存放后面一系列源码包,然后进入该目录
mkdir ~/build

  • 然后将上面的四个源码包进行解压
tar xzf nginx-1.13.7.tar.gz
tar xzf openssl-1.1.0g.tar.gz
tar xzf pcre-8.41.tar.gz
tar xzf zlib-1.2.11.tar.gz

②配置、编译、安装

  • 进入nginx目录

  • 配置:然后输入下面的命令进行编译前配置。configure命令做了大量的“幕后”工作,包括检测操作系统内核和已经安装的软件,参数 的解析,中间目录的生成以及根据各种参数生成一些C源码文件、Makefile文件等。其中的参数选项有:
    • --prefix:Nginx安装的根路径,所有其他的安装路径都要依赖于该选项。默认为/usr/local/nginx
    • --with-http_realip_module:安装http ssl module(该模块默认不会安装,此处我们显式安装)
    • --with-http_addition_module:安装http realip module(该模块默认不会安装,此处我们显式安装)
    • --with-http_gzip_static_module:安装http gzip static module(该模块默认不会安装,此处我们显式安装)
    • --with-http_secure_link_module:安装http secure link module(该模块默认不会安装,此处我们显式安装)
    • --with-http_stub_status_module:安装http stub status module(该模块默认不会安装,此处我们显式安装)指定
    • --with-stream:
    • --with-pcre=/home/dongshao/build/pcre-8.41:指定pcre库的源码位置,在编译Nginx时会进入该目录编译pcre源码(注意此处的路径改为你自己的路径)
    • --with-zlib=/home/dongshao/build/zlib-1.2.11:指定pcre库的源码位置(注意此处的路径改为你自己的路径)
    • --with-openssl=/home/dongshao/build/openssl-1.1.0g:指定openssl库的源码位置(注意此处的路径改为你自己的路径)
    • 此处的参数选项是根据我自己的需求选定的,如果你有自己的需求,那么就换成自己的参数选项(详情见下面的选项介绍)
./configure --prefix=/usr/local/nginx --with-http_realip_module --with-http_addition_module --with-http_gzip_static_module --with-http_secure_link_module --with-http_stub_status_module --with-stream --with-pcre=/home/dongshao/build/pcre-8.41 --with-zlib=/home/dongshao/build/zlib-1.2.11 --with-openssl=/home/dongshao/build/openssl-1.1.0g

  • ./configure命令完成之后会在nginx的目录下生成一个objs目录(该目录下面会详细介绍),该目录用于放置在configure命令执行后所生成的源文件及目录,以及make命令执行后生 成的目标文件和最终连接成功的二进制文件

  • 编译:输入make进行编译,make命令根据configure命令生成的Makefile文件编译Nginx工程,并生成目标文件、最终的二进制文件
make

  • 安装:make install命令根据configure执行时的参数将Nginx部署到指定的安装目录,包括相关目 录的建立和二进制文件、配置文件的复制
sudo make install

  • 安装完成之后在/usr/local/目录下面,产生了nginx的目录

Nginx相关目录与文件

  • ①安装目录:该目录存放实际Nginx服务运行期间所需要的二进制文件、配置文件等。默认情况下, 该目录为/usr/local/nginx(我们上面也是安装在这个目录下)

  • ②配置文件:配置文件能够决定Nginx及其模块的工作方式,Nginx默认的配置文件位于NgInx安装目录下的/conf目录中,在上面我们把nginx安装在/usr/local/nginx下,因为默认配置文件目录为/usr/local/nginx/conf/,启动nginx的默认配置文件为/usr/local/nginx/conf/nginx.conf

  • ③二进制文件:默认为/usr/local/nginx/sbin/nginx,启动的nginx程序就是这个

  • ④日志文件:日志文件通常会比较大,当研究Nginx的底层架构时,需要打开debug级别的日志,这个级别的日志非常详细,会导致日志文件的大小增长得极快,需要预先分配一个拥有更大磁盘空间的目录。日志文件的默认路径为/usr/local/nginx/logs

  • ⑤网页:默认路径为/usr/local/nginx/html,当我们初次安装好Nginx时,使用网页访问nginx,显示的网页就是这个目录下的index.html文件

三、configure的命令参数

  • 使用help命令可以查看configure包含的参数:
./configure --help
  • 这里不一一列出help的结果,只是把它的参数分为了四大类型,下面将会详述各类型下所有参数的用法和意义

①路径相关的参数

  • 下图列出了Nginx在编译期、运行期中与路径相关的各种参数

②编译相关的参数

  • 下图列出了编译Nginx时与编译器相关的参数

③依赖软件的相关参数

  • 下面是一些Nginx依赖的常用软件支持的参数

④模块相关的参数

  • 除了少量核心代码外,Nginx完全是由各种功能模块组成的。这些模块会根据配置参数 决定自己的行为,因此,正确地使用各个模块非常关键。在configure的参数中,我们把它们 分为五大类
    • 事件模块
    • 默认即编译进入Nginx的HTTP模块
    • 默认不会编译进入Nginx的HTTP模块
    • 邮件代理服务器相关的mail模块
    • 其他模块
  • 编译时选择下面的模块不会影响到运行性能,以后在配置使用这些模块时性能会产生影响
  • 1)事件模块:下图列出了Nginx可以选择哪些事件模块编译到产品中

  • 2)默认即编译进入Nginx的HTTP模块:下图列出了默认就会编译进Nginx的核心HTTP模块,以及如何把这些HTTP模块从产品 中去除

  • 3)默认不会编译进入Nginx的HTTP模块:下图列出了默认不会编译至Nginx中的HTTP模块以及把它们加入产品中的方法

  • 上图补充:
    • --with-http-gunzip_module:对于不支持gzip编码的客户,该模块用于为客户解压缩预压缩内容
  • 4)邮件代理服务器相关的mail模块:下图列出了把邮件模块编译到产品中的参数

⑤其他模块

  • configure还接收一些其他参数,下图中列出了相关参数的说明

四、configure执行流程

  • 我们看到configure命令支持非常多的参数,configure由Shell脚本编写,中间会调用<nginx-source>/auto/目录下的脚本。这里将只对configure脚本本身做分析,对于它所调用的auto目录下的其他工具脚本则只做功能性的说明
  • configure脚本的内容如下:
#!/bin/sh
# Copyright (C) Igor Sysoev
# Copyright (C) Nginx, Inc.
#auto/options脚本处理configure命令的参数。例如,如果参数是--help,那么显示支持的所有参数格式。options脚本会定义后续工作将要用到的变量,然后根据本次参数以及默认值设置这些变量
. auto/options
#auto/init脚本初始化后续将产生的文件路径。例如,Makefile、ngx_modules.c等文件默认情况下将会在<nginx-source>/objs/
. auto/init
#auto/sources脚本将分析Nginx的源码结构,这样才能构造后续的Makefile文件
. auto/sources
#编译过程中所有目标文件生成的路径由—builddir=DIR参数指定,默认情况下为<nginx-source>/objs,此时这个目录将会被创建
test -d $NGX_OBJS || mkdir $NGX_OBJS
#开始准备建立ngx_auto_headers.h、autoconf.err等必要的编译文件
echo > $NGX_AUTO_HEADERS_H
echo > $NGX_AUTOCONF_ERR
#向objs/ngx_auto_config.h写入命令行带的参数
echo "#define NGX_CONFIGURE \"$NGX_CONFIGURE\"" > $NGX_AUTO_CONFIG_H
#判断DEBUG标志,如果有,那么在objs/ngx_auto_config.h文件中写入DEBUG宏
if [ $NGX_DEBUG = YES ]; then
have=NGX_DEBUG . auto/have
fi
#现在开始检查操作系统参数是否支持后续编译
if test -z "$NGX_PLATFORM"; then
echo "checking for OS"
NGX_SYSTEM=`uname -s 2>/dev/null`
NGX_RELEASE=`uname -r 2>/dev/null`
NGX_MACHINE=`uname -m 2>/dev/null`
#屏幕上输出OS名称、内核版本、32位/64位内核
echo " + $NGX_SYSTEM $NGX_RELEASE $NGX_MACHINE"
NGX_PLATFORM="$NGX_SYSTEM:$NGX_RELEASE:$NGX_MACHINE";
case "$NGX_SYSTEM" in
MINGW32_*)
NGX_PLATFORM=win32
;;
esac
else
echo "building for $NGX_PLATFORM"
NGX_SYSTEM=$NGX_PLATFORM
fi
#检查并设置编译器,如GCC是否安装、GCC版本是否支持后续编译nginx
. auto/cc/conf
#对非Windows操作系统定义一些必要的头文件,并检查其是否存在,以此决定configure后续步骤是否可以成功
if [ "$NGX_PLATFORM" != win32 ]; then
. auto/headers
fi
#对于当前操作系统,定义一些特定的操作系统相关的方法并检查当前环境是否支持。例如,对于
Linux,在这里使用
sched_setaffinity设置进程优先级,使用
Linux特有的
sendfile系统调用来加速向网络中发送文件块
. auto/os/conf
#定义类UNIX 操作系统中通用的头文件和系统调用等,并检查当前环境是否支持
if [ "$NGX_PLATFORM" != win32 ]; then
. auto/unix
fi
#最核心的构造运行期
modules的脚本。它将会生成
ngx_modules.c文件,这个文件会被编译进
Nginx中,其中它所做的唯一的事情就是定义了
ngx_modules数组。
ngx_modules指明
Nginx运行期间有哪些模块会参与到请求的处理中,包括
HTTP请求可能会使用哪些模块处理,因此,它对数组元素的顺序非常敏感,也就是说,绝大部分模块在
ngx_modules数组中的顺序其实是固定的。例如,一个请求必须先执行
ngx_http_gzip_filter_module模块重新修改
HTTP响应中的头部后,才能使用
ngx_http_header_filter模块按照
headers_in结构体里的成员构造出以
TCP流形式发送给客户端的
HTTP响应头部。注意,我们在
--add-module=参数里加入的第三方模块也在此步骤写入到
ngx_modules.c文件中了
. auto/modules
#conf脚本用来检查Nginx在链接期间需要链接的第三方静态库、动态库或者目标文件是否存在
. auto/lib/conf
#处理Nginx安装后的路径
case ".$NGX_PREFIX" in
.)
NGX_PREFIX=${NGX_PREFIX:-/usr/local/nginx}
have=NGX_PREFIX value="\"$NGX_PREFIX/\"" . auto/define
;;
.!)
NGX_PREFIX=
;;
*)
have=NGX_PREFIX value="\"$NGX_PREFIX/\"" . auto/define
;;
esac
#处理Nginx安装后conf文件的路径
if [ ".$NGX_CONF_PREFIX" != "." ]; then
have=NGX_CONF_PREFIX value="\"$NGX_CONF_PREFIX/\"" . auto/define
fi
#处理Nginx安装后,二进制文件、pid、lock等其他文件的路径可参见configure参数中路径类选项的说明
have=NGX_SBIN_PATH value="\"$NGX_SBIN_PATH\"" . auto/define
have=NGX_CONF_PATH value="\"$NGX_CONF_PATH\"" . auto/define
have=NGX_PID_PATH value="\"$NGX_PID_PATH\"" . auto/define
have=NGX_LOCK_PATH value="\"$NGX_LOCK_PATH\"" . auto/define
have=NGX_ERROR_LOG_PATH value="\"$NGX_ERROR_LOG_PATH\"" . auto/define
have=NGX_HTTP_LOG_PATH value="\"$NGX_HTTP_LOG_PATH\"" . auto/define
have=NGX_HTTP_CLIENT_TEMP_PATH value="\"$NGX_HTTP_CLIENT_TEMP_PATH\"" . auto/define
have=NGX_HTTP_PROXY_TEMP_PATH value="\"$NGX_HTTP_PROXY_TEMP_PATH\"" . auto/define
have=NGX_HTTP_FASTCGI_TEMP_PATH value="\"$NGX_HTTP_FASTCGI_TEMP_PATH\"" . auto/define
have=NGX_HTTP_UWSGI_TEMP_PATH value="\"$NGX_HTTP_UWSGI_TEMP_PATH\"" . auto/define
have=NGX_HTTP_SCGI_TEMP_PATH value="\"$NGX_HTTP_SCGI_TEMP_PATH\"" . auto/define
#创建编译时使用的objs/Makefile文件
. auto/make
#为objs/Makefile加入需要连接的第三方静态库、动态库或者目标文件
. auto/lib/make
#为objs/Makefile加入install功能,当执行make install时将编译生成的必要文件复制到安装路径,建立必要的目录
. auto/install
# 在ngx_auto_config.h文件中加入NGX_SUPPRESS_WARN宏、NGX_SMP宏
. auto/stubs
#在ngx_auto_config.h文件中指定NGX_USER和NGX_GROUP宏,如果执行configure时没有参数指定,默认两者皆为nobody(也就是默认以nobody用户运行进程)
have=NGX_USER value="\"$NGX_USER\"" . auto/define
have=NGX_GROUP value="\"$NGX_GROUP\"" . auto/define
#显示configure执行的结果,如果失败,则给出原因
. auto/summary

五、configure生成的文件

  • 当configure执行成功时会生成objs目录,并在该目录下产生以下目录和文件:

  • 上述目录和文件介绍如下:
    • ①src目录用于存放编译时产生的目标文件
    • ②Makefile文件用于编译Nginx工程以及在加入install参数后安装Nginx
    • ③autoconf.err保存configure执行过程中产生的结果
    • ④ngx_auto_headers.h和ngx_auto_config.h保存了一些宏,这两个头文件会被src/core/ngx_config.h及src/os/unix/ngx_linu
    • ⑤ngx_modules.c是一个关键文件,我们需要看看它的内部结构。一个默认配置下生成的ngx_modules.c文件内容如下
#include <ngx_config.h>
#include <ngx_core.h>…
ngx_module_t *ngx_modules[] = {
    &ngx_core_module,
    &ngx_errlog_module,
    &ngx_conf_module,
    &ngx_events_module,
    &ngx_event_core_module,
    &ngx_epoll_module,
    &ngx_http_module,
    &ngx_http_core_module,
    &ngx_http_log_module,
    &ngx_http_upstream_module,
    &ngx_http_static_module,
    &ngx_http_autoindex_module,
    &ngx_http_index_module,
    &ngx_http_auth_basic_module,
    &ngx_http_access_module,
    &ngx_http_limit_zone_module,
    &ngx_http_limit_req_module,
    &ngx_http_geo_module,
    &ngx_http_map_module,
    &ngx_http_split_clients_module,
    &ngx_http_referer_module,
    &ngx_http_rewrite_module,
    &ngx_http_proxy_module,
    &ngx_http_fastcgi_module,
    &ngx_http_uwsgi_module,
    &ngx_http_scgi_module,
    &ngx_http_memcached_module,
    &ngx_http_empty_gif_module,
    &ngx_http_browser_module,
    &ngx_http_upstream_ip_hash_module,
    &ngx_http_write_filter_module,
    &ngx_http_header_filter_module,
    &ngx_http_chunked_filter_module,
    &ngx_http_range_header_filter_module,
    &ngx_http_gzip_filter_module,
    &ngx_http_postpone_filter_module,
    &ngx_http_ssi_filter_module,
    &ngx_http_charset_filter_module,
    &ngx_http_userid_filter_module,
    &ngx_http_headers_filter_module,
    &ngx_http_copy_filter_module,
    &ngx_http_range_body_filter_module,
    &ngx_http_not_modified_filter_module,
    NULL
};
  • ngx_modules.c文件就是用来定义ngx_modules数组的
  • ngx_modules是非常关键的数组,它指明了每个模块在Nginx中的优先级,当一个请求同时符合多个模块的处理规则时,将按照它们在ngx_modules数组中的顺序选择最靠前的模块优先处理。对于HTTP过滤模块而言则是相反的,因为HTTP框架在初始化时,会在ngx_modules数组中将过滤模块按先后顺序向过滤链表中添加,但每次都是添加到链表的表头。因此,对HTTP过滤模块而言,在ngx_modules数组中越是靠后反而会首先处理
  • 因此,ngx_modules中模块的先后顺序非常重要,不正确的顺序会导致Nginx无法工作,这是auto/modules脚本执行后的结果
  • 可以看出,在安装过程中,configure做了大量的幕后工作,我们需要关注在这个过程中Nginx做了哪些事情。configure除了寻找依赖的软件外,还针对不同的UNIX操作系统做了许多优化工作。这是Nginx跨平台的一种具体实现,也体现了Nginx追求高性能的一贯风格
  • configure除了生成Makefile外,还生成了ngx_modules.c文件,它决定了运行时所有模块的优先级(在编译过程中而不是编码过程中)。对于不需要的模块,既不会加入ngx_modules数组,也不会编译进Nginx产品中,这也体现了轻量级的概念

六、安装第三方模块

  • 由于有多个开源项目,所以在 Nginx 周围就会有一个活跃的开发社区。由于 Nginx 模块化特性,这个社区能够开发和发布模块,从而为 Nginx 提供额外的功能。它们涵盖了 广泛的应用,所以着手开发自己的模块之前应该看看有什么可用模块

第三方模块的安装步骤

  • ①定位你想要使用的模块
  • ②下载该模块
  • ③解压缩源代码安装包。
  • ④如果有README文件,那么阅读README文件, 查看在安装中是否有依赖安装
  • ⑤通过下面的命令选项配置使用该模块
./configure -add-module=<path>
  • 这个过程会给你的 nginx 进制文件与模块附加这个功能
  • 需要注意的是,很多第 方模块是实验性质的。因此,在将这些模块用于生产系统之前,首先要测试使用这些模块。另外请记住, Nginx 的开发版本中可能会有API的变化, 会导致第三方模块出现问题

七、Linux内核参数的优化

  • 由于默认的Linux内核参数考虑的是最通用的场景,这明显不符合用于支持高并发访问 的Web服务器的定义,所以需要修改Linux内核参数,使得Nginx可以拥有更高的性能
  • 在优化内核时,可以做的事情很多,不过,我们通常会根据业务特点来进行调整,当 Nginx作为静态Web内容服务器、反向代理服务器或是提供图片缩略图功能(实时压缩图片) 的服务器时,其内核参数的调整都是不同的。这里只针对最通用的、使Nginx支持更多并发 请求的TCP网络参数做简单说明
  • 首先,需要修改/etc/sysctl.conf来更改内核参数。例如,最常用的配置:
fs.file-max = 999999
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.ip_local_port_range = 1024 61000
net.ipv4.tcp_rmem = 4096 32768 262142
net.ipv4.tcp_wmem = 4096 32768 262142
net.core.netdev_max_backlog = 8096
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.core.rmem_max = 2097152
net.core.wmem_max = 2097152
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn.backlog=1024
  • 然后执行sysctl-p命令,使上述修改生效
  • 上面的参数意义解释如下:
    • file-max:这个参数表示进程(比如一个worker进程)可以同时打开的最大句柄数,这 个参数直接限制最大并发连接数,需根据实际情况配置
    • tcp_tw_reuse:这个参数设置为1,表示允许将TIME-WAIT状态的socket重新用于新的 TCP连接,这对于服务器来说很有意义,因为服务器上总会有大量TIME-WAIT状态的连接
    • tcp_keepalive_time:这个参数表示当keepalive启用时,TCP发送keepalive消息的频度。 默认是2小时,若将其设置得小一些,可以更快地清理无效的连接
    • tcp_fin_timeout:这个参数表示当服务器主动关闭连接时,socket保持在FIN-WAIT-2状 态的最大时间
    • tcp_max_tw_buckets:这个参数表示操作系统允许TIME_WAIT套接字数量的最大值, 如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。该参数默认为 180000,过多的TIME_WAIT套接字会使Web服务器变慢
    • tcp_max_syn_backlog:这个参数表示TCP三次握手建立阶段接收SYN请求队列的最大 长度,默认为1024,将其设置得大一些可以使出现Nginx繁忙来不及accept新连接的情况时, Linux不至于丢失客户端发起的连接请求
    • ip_local_port_range:这个参数定义了在UDP和TCP连接中本地(不包括连接的远端) 端口的取值范围
    • net.ipv4.tcp_rmem:这个参数定义了TCP接收缓存(用于TCP接收滑动窗口)的最小 值、默认值、最大值
    • net.ipv4.tcp_wmem:这个参数定义了TCP发送缓存(用于TCP发送滑动窗口)的最小 值、默认值、最大值
    • netdev_max_backlog:当网卡接收数据包的速度大于内核处理的速度时,会有一个队列 保存这些数据包。这个参数表示该队列的最大值
    • rmem_default:这个参数表示内核套接字接收缓存区默认的大小
    • wmem_default:这个参数表示内核套接字发送缓存区默认的大小
    • rmem_max:这个参数表示内核套接字接收缓存区的最大大小
    • wmem_max:这个参数表示内核套接字发送缓存区的最大大小
    • tcp_syncookies:该参数与性能无关,用于解决TCP的SYN攻击
  • 注意:
    • 滑动窗口的大小与套接字缓存区会在一定程度上影响并发连接的数目。每个 TCP连接都会为维护TCP滑动窗口而消耗内存,这个窗口会根据服务器的处理速度收缩或扩 张
    • 参数wmem_max的设置,需要平衡物理内存的总大小、Nginx并发处理的最大连接数量 (由nginx.conf中的worker_processes和worker_connections参数决定)而确定。当然,如果仅仅 为了提高并发量使服务器不出现Out Of Memory问题而去降低滑动窗口大小,那么并不合 适,因为滑动窗口过小会影响大数据量的传输速度。rmem_default、wmem_default、 rmem_max、wmem_max这4个参数的设置需要根据我们的业务特性以及实际的硬件成本来综 合考虑。

  • 我是小董,V公众点击"笔记白嫖"解锁更多【Nginx】资料内容。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

董哥的黑板报

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值