nginx源码分析和openresty源码分析

nginx

nginx可以作为网关(负载均衡,路由规则,限流,访问控制),缓存服务器,web服务器(可以使用lua开发,openresty框架),反向代理服务器。
支持http,https,http/2,grpc,tcp,udp,websocket协议。

源码结构

src/core (底层核心结构)

启动入口和基础的数据结构和算法。
nginx.c就是入口,初始化,启动多进程。

数据结构
ngx_array
ngx_buf
ngx_conf_flie
ngx_connection
ngx_core
ngx_file
ngx_list
ngx_log
ngx_module
ngx_open_file_cache
ngx_parse_time
ngx_inet
ngx_queue
ngx_radixtree
ngx_rbtree
ngx_resolver
ngx_rwlock
ngx_shmtx
ngx_sha1
ngx_slab
ngx_spinlock
ngx_times
ngx_thread_pool
可以分析出来数据结构分成几类:
一类是通用数据结构,类似c++的stl
一种是网络文件锁相关的结构
一种是内存池线程池相关的结构
还有其他的基数树,红黑树,日志模块等等。

算法
ngx_crc
ngx_crc32
ngx_crypt
ngx_hash
ngx_md5
ngx_regex
都是一些通用算法加解密,哈希,正则,差错校验

src/os(底层封装操作系统相关)

都是一些glibc提供的接口封装,包括
内存分配,原子操作,网络通信,动态库dlopen等(模块功能核心),文件系统,进程线程管理,共享内存等等。

src/event (高性能事件相关)

封装了epoll,定时器,管道,openssl等等

src/http (http模块相关)

就是http协议的实现

src/mail (邮件协议相关)

邮件协议的实现,主要就是通知管理员的作用

src/stream (stream相关)

stream的实现,也就是处理四层协议

src/misc

测试和性能分析相关

实现细节

在这里插入图片描述

进程模型

main函数初始化时间,日志,池资源,slab,crc32,信号,pid文件等等之后
执行ngx_master_process_cycle开始执行启动master和worker的流程。

初始化关键函数:ngx_init_cycle
每个工作进程的核心数据结构:ngx_cycle_t

ngx_start_worker_processes->ngx_spawn_process启动工作线程,工作线程初始化socket通信管道后进入自己的循环流程ngx_worker_process_cycle。

1.主进程之后如果需要的话会初始化缓存进程,然后进入监控其他进程的循环。

2.工作线程接下来需要执行的就是模块初始化
在这里插入图片描述

核心模块

nginx核心功能实现都在模块里面,所以主要关注点在模块。

ngx_core_module是核心数据结构,初始化模块,模块指令模块上下文都在这里。
ngx_core_module->ngx_core_commands->load_module则是加载其他模块的入口。

其他子模块的核心模块:
ngx_event_core_module
ngx_http_core_module
ngx_mail_core_module
ngx_stream_core_module

http模块

handler:负责 处理请求并返回
核心函数:ngx_create_listening,ngx_http_init_connection,ngx_http_wait_request_handler
,ngx_http_handler

filter:过滤,流量控制
核心函数:ngx_http_top_header_filter,ngx_http_top_body_filter,ngx_http_top_request_body_filter

upstream:反向代理
核心函数:ngx_http_upstream_init,ngx_http_upstream_add,ngx_http_upstream_bind_set_slot

load balance:负载均衡
核心函数:根据配置选择对应的负载均衡模块
ngx_http_upstream_hash_module,ngx_http_upstream_random_module
ngx_http_upstream_ip_hash_module,ngx_http_upstream_least_conn_module

内存池模型

每个连接分配自己的内存池,连接断开,统一回收。

进程间通信和同步模型

进程间通信使用了:
共享内存(一般使用mmap,也有使用shmget的):封装接口 ngx_shm_alloc
信号:ngx_signal_handler处理信号
套接字:ngx_channel_t封装了使用socketpair生成socket对,作为父子进程间通信方案。

同步使用了:
原子操作:ngx_atoymic_cmp_set,原子操作还作为自旋锁ngx_spinlock的底层实现。
信号量:ngx_shmtx_create封装了sem_init,信号量可能会使进程睡眠,ngx_shmtx_lock底层就是信号量实现。
文件锁:ngx_trylock_fd,使用fcntl实现,F_SETLK(会返回失败)和F_SETLKW(会一直获取直到成功)。其中第三个参数flock就是文件锁结构体,可以精确锁住文件的一部分内容。

惊群问题

accept惊群
linux4.5版本以后设置epoll的标志位EPOLLEXCLUSIVE可以解决,SO_REUSEPORT也可以。

旧版本可以使用accept_mutex,但是会引起cpu负载不均衡问题和性能下降问题。

accept_mutex

accept_mutex原理是同一时间内只运行一个进程listen这个端口的套接字。
需要注意这个锁是进程锁,需要放在共享内存里。
ngx_shmtx_trylock加锁,使用cas,将自己的进程号作为交互标志。
没有拿到锁的进程会进入等待事件,时间是ngx_accept_mutex_delay
处理好accept连接后通过ngx_event_process_posted发布事件到ngx_posted_accept_events(accept接收队列)
然后释放锁,并使用ngx_shmtx_wakeup唤醒其他进程(信号量实现)
然后发布事件到ngx_posted_events(其他事件多列)

openresty

在nginx基础上加入数据库缓存加解密中间件等lua库,可扩展性变得很强,迭代速度快。通过nginx模块的方式加入nginx,对原生nginx不需要做代码改造,可维护性好。

核心组成:nginx,luajit,ngx_lua(http_lua),stream_lua

在这里插入图片描述
直接在配置文件里写lua代码

luajit

传统c和lua交互方式

使用栈

c和luajit交互

使用ffi库可以直接调用c函数,还可以调用so动态库

图解

调用自己的lua代码原理:模块中预留了接口或者hook点,其实就是函数指针,执行到这些点就会读取配置里的代码编译执行字节码或者直接执行机器码。
在这里插入图片描述
在这里插入图片描述

参数优化

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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值