第七周作业

1.

Select模型:select系统调用将轮询 的操作交给了内核来帮我们完成,从而避免在用户空间不断发起的轮询所带来的系统开销。

1 用户态发起 select 调用: 在用户态,应用程序执行 select 系统调用,此时用户线程会被阻塞。 select 用于让内核帮忙监视一组文件描述符(fd)是否就绪。 2 拷贝 fd 数组到内核态: 将需要监视的文件描述符数组从用户态拷贝到内核态。这样内核才能对这些文件描述符进行后续检查。 3 内核态遍历检查: 在内核态,内核开始遍历接收到的文件描述符数组,查找其中哪些文件描述符对应的 I/O 操作已经就 绪。 比如检查哪些fd对应的socket套接字有数据可读,哪些可以进行写操作等。 4 标记就绪 fd: 内核找到就绪的文件描述符后,会将这些就绪 I/O 对应的文件描述符数组Bitmap的值位置标记为 1, 若没有数据到来,则为0。从而实现标记哪些文件描述符是就绪的。 5 拷贝结果回用户态: 内核将修改后的文件描述符数组拷贝回用户态。 5 用户态遍历查找: 在用户态,阻塞被解除,用户线程开始遍历文件描述符数组,寻找那些被标记为就绪的文件描述符,然后 对这些就绪的文件描述符进行相应的 I/O 操作。 操作完毕后,需要重置fd数组,并需要重新调用select传入充值后的fd数组,让内核发起新一轮遍历轮 询。

poll模型:没有最大文件描述符数量的限制(基于链表存储)的select

epoll模型:使用epoll专用的文件描述符和内核中的红黑树及就绪队列。 

用户空间 epoll_create:用户空间通过调用epoll_create函数在内核空间创建一个 epoll 实例。- 红黑树(rbr)用于管理所有被监控的文件描述符(如 socket)- 就绪链表(rdllist)用于存放有事件发生(就绪)的文件描述符- 等待队列(wq)用于存储等待事件发生的进程。 epoll_ctl:调用epoll_ctl函数可向已创建的 epoll 实例中添加|修改|删除需要监控的 socket。- 添加时,对应的 socket 信息会被添加到红黑树中进行管理。 epoll_wait:用户空间调用epoll_wait函数,主动放弃 CPU 资源进入等待状态。- 此时内核会检查就绪队列中是否有就绪的文件描述符。- 若有,内核会唤醒对应的用户进程,并返回相关事件信息;- 若无,则进程会一直等待,直到有事件发生或者超时。

2.

#!/bin/bash

# Nginx 编译安装脚本
# 适用于 CentOS/RHEL 和 Ubuntu/Debian 系统

# 定义版本和安装路径
NGINX_VERSION="1.24.0"
PCRE_VERSION="8.45"
ZLIB_VERSION="1.2.13"
OPENSSL_VERSION="3.0.8"
NGINX_PREFIX="/usr/local/nginx"
SOURCE_DIR="/usr/local/src"

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # 无颜色

# 错误处理函数
handle_error() {
    echo -e "${RED}错误: $1${NC}"
    exit 1
}

# 检查是否为 root 用户
check_root() {
    if [ "$(id -u)" -ne 0 ]; then
        handle_error "请使用 root 用户运行此脚本"
    fi
}

# 安装依赖
install_dependencies() {
    echo -e "${YELLOW}正在安装编译依赖...${NC}"
    
    # 检测操作系统
    if [ -f /etc/redhat-release ]; then
        # CentOS/RHEL
        yum install -y wget gcc gcc-c++ make libtool tar gzip || handle_error "依赖安装失败"
    elif [ -f /etc/debian_version ]; then
        # Ubuntu/Debian
        apt-get update || handle_error "更新软件源失败"
        apt-get install -y wget build-essential libtool tar gzip || handle_error "依赖安装失败"
    else
        handle_error "不支持的操作系统"
    fi
    
    echo -e "${GREEN}依赖安装完成${NC}"
}

# 创建目录
create_directories() {
    echo -e "${YELLOW}正在创建目录...${NC}"
    mkdir -p "$SOURCE_DIR" || handle_error "创建源目录失败"
    mkdir -p "$NGINX_PREFIX" || handle_error "创建安装目录失败"
    echo -e "${GREEN}目录创建完成${NC}"
}

# 下载源码
download_sources() {
    echo -e "${YELLOW}正在下载源码...${NC}"
    cd "$SOURCE_DIR" || handle_error "无法进入源目录"
    
    # 下载 Nginx
    if [ ! -f "nginx-$NGINX_VERSION.tar.gz" ]; then
        wget "https://nginx.org/download/nginx-$NGINX_VERSION.tar.gz" || handle_error "下载 Nginx 失败"
    fi
    
    # 下载 PCRE
    if [ ! -f "pcre-$PCRE_VERSION.tar.gz" ]; then
        wget "https://ftp.pcre.org/pub/pcre/pcre-$PCRE_VERSION.tar.gz" || handle_error "下载 PCRE 失败"
    fi
    
    # 下载 Zlib
    if [ ! -f "zlib-$ZLIB_VERSION.tar.gz" ]; then
        wget "https://zlib.net/zlib-$ZLIB_VERSION.tar.gz" || handle_error "下载 Zlib 失败"
    fi
    
    # 下载 OpenSSL
    if [ ! -f "openssl-$OPENSSL_VERSION.tar.gz" ]; then
        wget "https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz" || handle_error "下载 OpenSSL 失败"
    fi
    
    echo -e "${GREEN}源码下载完成${NC}"
}

# 解压源码
extract_sources() {
    echo -e "${YELLOW}正在解压源码...${NC}"
    cd "$SOURCE_DIR" || handle_error "无法进入源目录"
    
    # 解压 Nginx
    if [ ! -d "nginx-$NGINX_VERSION" ]; then
        tar -zxf "nginx-$NGINX_VERSION.tar.gz" || handle_error "解压 Nginx 失败"
    fi
    
    # 解压 PCRE
    if [ ! -d "pcre-$PCRE_VERSION" ]; then
        tar -zxf "pcre-$PCRE_VERSION.tar.gz" || handle_error "解压 PCRE 失败"
    fi
    
    # 解压 Zlib
    if [ ! -d "zlib-$ZLIB_VERSION" ]; then
        tar -zxf "zlib-$ZLIB_VERSION.tar.gz" || handle_error "解压 Zlib 失败"
    fi
    
    # 解压 OpenSSL
    if [ ! -d "openssl-$OPENSSL_VERSION" ]; then
        tar -zxf "openssl-$OPENSSL_VERSION.tar.gz" || handle_error "解压 OpenSSL 失败"
    fi
    
    echo -e "${GREEN}源码解压完成${NC}"
}

# 编译安装 Nginx
compile_nginx() {
    echo -e "${YELLOW}正在编译安装 Nginx...${NC}"
    cd "$SOURCE_DIR/nginx-$NGINX_VERSION" || handle_error "无法进入 Nginx 源码目录"
    
    # 配置
    ./configure \
        --prefix="$NGINX_PREFIX" \
        --with-pcre="$SOURCE_DIR/pcre-$PCRE_VERSION" \
        --with-zlib="$SOURCE_DIR/zlib-$ZLIB_VERSION" \
        --with-openssl="$SOURCE_DIR/openssl-$OPENSSL_VERSION" \
        --with-http_ssl_module \
        --with-http_v2_module \
        --with-http_gzip_static_module \
        --with-http_stub_status_module \
        --with-threads \
        --with-stream \
        --with-stream_ssl_module || handle_error "Nginx 配置失败"
    
    # 编译
    make -j "$(nproc)" || handle_error "Nginx 编译失败"
    
    # 安装
    make install || handle_error "Nginx 安装失败"
    
    echo -e "${GREEN}Nginx 编译安装完成${NC}"
}

# 创建系统服务
create_systemd_service() {
    echo -e "${YELLOW}正在创建系统服务...${NC}"
    
    cat > /etc/systemd/system/nginx.service << EOF
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=$NGINX_PREFIX/logs/nginx.pid
ExecStartPre=$NGINX_PREFIX/sbin/nginx -t
ExecStart=$NGINX_PREFIX/sbin/nginx
ExecReload=$NGINX_PREFIX/sbin/nginx -s reload
ExecStop=$NGINX_PREFIX/sbin/nginx -s stop
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF
    
    # 重载 systemd
    systemctl daemon-reload || handle_error "重载 systemd 失败"
    
    # 设置开机启动
    systemctl enable nginx || handle_error "设置 Nginx 开机启动失败"
    
    echo -e "${GREEN}Nginx 系统服务创建完成${NC}"
}

# 配置防火墙
configure_firewall() {
    echo -e "${YELLOW}正在配置防火墙...${NC}"
    
    # 检测操作系统
    if [ -f /etc/redhat-release ]; then
        # CentOS/RHEL
        if command -v firewalld >/dev/null 2>&1 && systemctl is-active firewalld >/dev/null 2>&1; then
            firewall-cmd --permanent --add-service=http || handle_error "添加 HTTP 服务到防火墙失败"
            firewall-cmd --permanent --add-service=https || handle_error "添加 HTTPS 服务到防火墙失败"
            firewall-cmd --reload || handle_error "重载防火墙失败"
            echo -e "${GREEN}防火墙配置完成${NC}"
        else
            echo -e "${YELLOW}Firewalld 未运行,跳过防火墙配置${NC}"
        fi
    elif [ -f /etc/debian_version ]; then
        # Ubuntu/Debian
        if command -v ufw >/dev/null 2>&1 && ufw status | grep -q "Status: active"; then
            ufw allow "Nginx Full" || handle_error "添加 Nginx 规则到防火墙失败"
            echo -e "${GREEN}防火墙配置完成${NC}"
        else
            echo -e "${YELLOW}UFW 未运行,跳过防火墙配置${NC}"
        fi
    fi
}

# 验证安装
verify_installation() {
    echo -e "${YELLOW}正在验证安装...${NC}"
    
    # 检查 Nginx 版本
    "$NGINX_PREFIX/sbin/nginx" -v || handle_error "Nginx 版本检查失败"
    
    # 启动 Nginx
    systemctl start nginx || handle_error "启动 Nginx 失败"
    
    # 检查 Nginx 状态
    systemctl is-active --quiet nginx || handle_error "Nginx 未运行"
    
    echo -e "${GREEN}Nginx 安装验证通过${NC}"
    echo -e "${GREEN}Nginx 已安装在: $NGINX_PREFIX${NC}"
    echo -e "${GREEN}Nginx 配置文件位于: $NGINX_PREFIX/conf/nginx.conf${NC}"
    echo -e "${GREEN}使用 systemctl 命令管理 Nginx:${NC}"
    echo -e "${YELLOW}启动: systemctl start nginx${NC}"
    echo -e "${YELLOW}停止: systemctl stop nginx${NC}"
    echo -e "${YELLOW}重启: systemctl restart nginx${NC}"
    echo -e "${YELLOW}重载配置: systemctl reload nginx${NC}"
}

# 主函数
main() {
    check_root
    install_dependencies
    create_directories
    download_sources
    extract_sources
    compile_nginx
    create_systemd_service
    configure_firewall
    verify_installation
    
    echo -e "${GREEN}Nginx 安装完成!${NC}"
}

# 执行主函数
main    

3.- 新版本或配置准备: 准备好新版本的 Nginx 可执行文件或配置文件,并确保它们没有问题- 新版本资源替换旧版本资源: 进行资源替换,此步骤要备份旧版本资源,可以用作回滚- 发送信号: 使用 nginx -s SIGUSR2,nginx -s reload 等方式向 Nginx 主进程发送重新加载的信号- 新的工作进程启动: Nginx 主进程接收到重新加载信号后,会启动新的工作进程,并使用新的配置文件或软件版本- 平滑过渡: 新的工作进程逐渐接管现有的连接。现有的连接会在旧的工作进程中继续处理,而新的连接会由新的工作 进程处理- 旧的进程退出: 当旧的工作进程不再有活动连接时,它会被关闭

4.

# --- 全局配置段 ---
user ...;
 worker_processes ...;
 ...
 #所有变量查询索引
# --- 事件驱动相关的配置 ---
events {
 ...;
 }
 # --- http/https 协议相关配置段 --
http {
 ...;
 server {
 ...;
 location {
 ...;
 }
 }
 }

# --- mail 协议相关配置段,默认被注释 --
mail {
 server {
 ...
 }
 }
 # --- stream 协议相关配置 --
stream {
 ...;
 }

5.

创建日志格式
root@ubuntu24:~# cat > log <<-eof
 #自定义访问日志格式 - 字符串
log_format basic '\$remote_addr - \$remote_user [\$time_local] 
"\$request" '
 '\$status \$body_bytes_sent "\$http_referer" '
 '"\$http_user_agent" "\$http_x_forwarded_for"';
 eof
 #自定义访问日志格式 - json 字符串   
log_format json_basic '{"remote_addr": "\$remote_addr", '
 '"remote_user": "\$remote_user", '
 '"time_local": "\$time_local", '
 '"request": "\$request", '
 '"status": "\$status", '
 '"body_bytes_sent": "\$body_bytes_sent", '
 '"http_referer": "\$http_referer", '
 '"http_user_agent": "\$http_user_agent", '
 '"http_x_forwarded_for": "\$http_x_forwarded_for"}';
添加配置
root@ubuntu24:~# num=$(grep -n access_log /etc/nginx/nginx.conf  | awk -F':' 
'{print $1}')
 root@ubuntu24:~# let num-=2
 root@ubuntu24:~# sed -i "${num}r log" /etc/nginx/nginx.conf

因为日志文件需要创建,所以,需要有对应的权限
root@ubuntu24:~# grep user /etc/nginx/nginx.conf
 user www-data;
 root@ubuntu24:~# chown -R www-data:www-data /var/log/nginx/

 

定制配置文件
root@ubuntu24:~# cat > /etc/nginx/conf.d/vhost.conf <<-eof
 server {
 listen 80 default_server;
 access_log /var/log/nginx/\${host}_access.log basic;
 location /web1/ {
 alias /data/server/nginx/web1/;
 }
 # 此资源记录json日志
location /json{
 access_log /var/log/nginx/\${host}_json_access.log json_basic;
 return 200 "json\n";
 }
 #不记录access log
 location /test{           
access_log off;                                                 
return 200 "test\n";
 }
 }
 eof
重启服务
root@ubuntu24:~# systemctl restart nginx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值