leevis.com icon indicating copy to clipboard operation
leevis.com copied to clipboard

Blog

Results 122 leevis.com issues
Sort by recently updated
recently updated
newest added

### golang程序性能分析 前段时间,花了2个多月用golang重写了我们的计费系统。利用tcpcopy把线上流量导入测试的时候,发现mysql计费测试慢了20分钟。因为存储类计费需要在计费程序里面算时长,还要根据分钟merge一次。所以,根据日志很难分析出哪个环节慢。 还好之前开发的时候已经就集成了`net/http/pprof`这个库的功能。提供出了http接口查看运行时的内存堆栈等。具体使用可以看下我[goframe debug/pprof](https://github.com/vislee/goframe/blob/master/srv/httpSrv.go#L70)的实现。就不多说了。 + 利用[go-torch](https://github.com/uber/go-torch)这个工具,直接可以生成调用栈的火焰图。 使用说明: - 按照文档说明安装该工具 `go get github.com/uber/go-torch` - 找个目录`clone` 该项目[FlameGraph](https://github.com/brendangregg/FlameGraph) - 把`clone`下来的目录加入到PATH. 我是临时使用,只加了个临时路径 `export PATH=$PATH:~/work/github.com/brendangregg/FlameGraph` - 然后使用命令生成火焰图。 `go-torch --time=120 --file "./mysql_1.svg" --url http://127.0.0.1:8080/debug/pprof` 。...

### 背景 近期遇到一个问题,源站接受请求后无响应或者响应时间非常长,客户端长连接测试。 一个连接发了多个请求,等不到响应时关闭连接。查看access日志时只有第一个请求的一条日志4,error日志也没详细的错误。 接下来就看看nginx是怎么处理http的pipeline请求的。 ### 代码分析 先看个测试例子: ```nginx-tests use Test::Nginx::Socket::Lua; use Cwd qw(cwd); log_level('debug'); repeat_each(1); plan tests => repeat_each() * (7 * blocks()); no_long_string(); run_tests(); __DATA__ === TEST 1:...

### 概述 nginx的变量为nginx配置添加了很多的灵活性。变量也在nginx中随处可见。例如日志的格式就使用了变量。 ### 变量的添加 在nginx http模块中,每个ctx的preconfiguration基本都是用来添加变量了。nginx中的变量有三种添加方式, 其一是已经有的变量,如:‘$binary_remote_addr’,二是配置文件生成的变量,如:‘set $name "liwq";’ 三是通过正则表达式捕获来生成变量,例如:server_name ~^(www\.)?(?\.+)$; 通过$domain 就可以访问这个捕获的变量了。 我们先来看下第一种变量是如何添加的? 在ngx_http_core_module_ctx的ngx_http_core_preconfiguration中,调用了ngx_http_variables_add_core_vars函数。该函数循环一个变量数组,调用ngx_hash_add_key把变量添加到cmcf->variables_keys中,前缀变量($http_xxx)会添加到cmcf->prefix_variables中。 第二种是直接调用ngx_http_get_variable_index函数,该函数的含义是直接向cmcf->variables数组中添加一个类型为ngx_http_variable_t的变量,直接返回数组下标。取值的时候直接调用ngx_http_get_indexed_variable函数。 第三种是正则编译变量,调用ngx_http_regex_compile 函数。 #### 添加变量代码分析 通过分析代码来看下变量是如何被添加的。 1. 已有的变量 ngx_http_core_module模块提供了大部分的变量,主要是请求头相关的。 调用栈:ngx_http_core_preconfiguration->ngx_http_variables_add_core_vars->ngx_http_add_variable 在ngx_http_variables_add_core_vars函数中,先调用了ngx_hash_keys_array_init函数初始化了添加变量所需要的结构体。参考[《hash表源码分析》](https://github.com/vislee/leevis.com/issues/63) 在ngx_http_variables_add_core_vars函数中循环调用ngx_http_add_variable函数,该函数又调用ngx_hash_add_key函数把变量添加到cmcf->variables_keys->keys 这个数组中。参考《hash表源码分析》。 前缀变量则调用ngx_http_add_prefix_variable函数把变量添加到cmcf->prefix_variables数组中。...

nginx

nginx location 的匹配顺序 nginx的官方文档location支持以下几种形式的配置, ``` location [ = | ~ | ~* | ^~ ] uri { ... } location @name { ... } ``` 注:在实际配置中符号和后面的uri中间有没有空格效果是一样的。 我们一般也就用三种配置,= 精确匹配,[^\~] 前缀匹配,\~或\~* 正则匹配。...

nginx

### 概述 ngx_buf 和 buf_chain 在nginx 被广泛使用,主要用在网络读。 ```c struct ngx_buf_s { u_char *pos; // 未处理内存开始 u_char *last; // 未处理内存结束 off_t file_pos; off_t file_last; u_char *start; /* start of buffer */...

nginx

### 概述 upstream是nginx向上游发起tcp请求的一种机制。在nginx中有很多有用的模块都用到了该机制,例如proxy模块,memcache模块等。 upstream模块提供了两个配置指令:upstream和server来指定上游服务器地址。 ### 指令解析 upstream机制的实现是在ngx_http_upstream.h|c, ngx_http_upstream_round_robin.h|c 这几个文件中。 同时使用upstream的模块(如proxy)也会初始化和调用ups模块的一些变量和函数,先从程序启动解析配置指令开始。调用逻辑在ngx_http_block函数中。 + 首先会调用ups模块ctx的函数指针指向的ngx_http_upstream_create_main_conf函数创建一个结构体保存配置: ```c typedef struct { ngx_hash_t headers_in_hash; ngx_array_t upstreams; // upstream数组,多组上游服务器 /* ngx_http_upstream_srv_conf_t */ } ngx_http_upstream_main_conf_t; ``` + 同时,也会调用proxy模块ctx的ngx_http_proxy_create_loc_conf创建一个结构体保存配置:...

nginx

# nginx hash表源码分析 nginx中,http请求头、变量、虚拟主机用到了hash表。hash表的实现在在ngx_hash.h和ngx_hash.c文件中。 根据使用场景,nginx的hash表只有初始化hash表和查找指定key的元素两个方法,不需要增加删除元素。在nginx程序启动时初始化hash表,处理请求过程中查找hash表。 nginx的hash表是通过挂链法解决冲突。因为不需要增加删除元素,所以在实现上不是通过链表而是计算对应bucket的元素个数一次性分配对应大小的数组存储冲突元素的。在分配数组时考虑了cpu 缓存的大小,从而加快查找速度。 ## 通用hash表(不带通配符) ### 使用例子 ```c // 初始化hash table(headers_in_hash) static ngx_int_t ngx_http_init_headers_in_hash(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) { ngx_array_t headers_in; ngx_hash_key_t *hk; ngx_hash_init_t hash; ngx_http_header_t *header;...

nginx
picture

nginx作为代理服务器,需要读取body后转发。以proxy_pass这个指令为例说明。如下: ``` ngx_http_read_client_request_body(r, ngx_http_upstream_init) ``` 读取body后向上游发起请求。在此暂时不介绍upstream相关的,仅仅介绍读取body。 首先会为保存body分配如下一个结构体: ```c typedef struct { ngx_temp_file_t *temp_file; // 临时文件 ngx_chain_t *bufs; // 保存了读取到的body位置,可能是在内存,也可能在文件 ngx_buf_t *buf; // 读取body缓存区 off_t rest; // 未读取body大小 off_t received; //...

nginx
picture

### 概述 nginx 通过封装ngx_http_script.h|c这两个文件支持脚本。在nginx内部,脚本正则变量是混在一起使用的。例如:ngx_http_rewrite_module 中if的实现rewrite的实现。 和动态语言类似,需要先把脚本编译然后再执行。 编译的过程基本就是向三个数组(flushes、lengths、values)中添加回调和内容,执行是遍历其中的2个数组(lengths 、values)调用编译阶段添加的回调函数。 ### 代码分析 #### 数据结构: ```c // 常量回调 typedef struct { ngx_http_script_code_pt code; uintptr_t len; } ngx_http_script_copy_code_t; // 变量回调 typedef struct { ngx_http_script_code_pt...

nginx

nginx框架通过upstream这个机制可以和上游服务器建立4层的连接。 http模块通过一个扩展的模块ngx_http_proxy_module.c提供了一个proxy_pass的命令支持7层的反向代理的功能。 下面就通过代码来看下nginx是如何实现的。 ## 配置解析与初始化 ### upstream 模块 ```ini upstream backend { server backend1.example.com weight=5; server 127.0.0.1:8080 max_fails=3 fail_timeout=30s; server unix:/tmp/backend3; server backup1.example.com backup; } ``` upstream实现在ngx_http_upstream_module中,通过定义两个配置指令来配置上游服务器地址。 upstream的模块也是从定义了ngx_module_t。ctx定义了3个函数,ngx_http_upstream_add_variables添加了变量,ngx_http_upstream_create_main_conf创建配置文件所需要的内存结构。ngx_http_upstream_init_main_conf初始化配置结果。通过upstream指令可以配置一组上游服务器,该指令在nginx框架由ngx_http_upstream函数处理,把upstream的srv挂到upstream模块main配置的数组上(`uscfp = ngx_array_push(&umcf->upstreams);`)。在upstream...