wenqiang li
wenqiang li
+ lua中每个值都可以具有元表。元表中的方法称为元方法,定义原始值的一些行为。 - **setmetatable(table,metatable)**: 对指定table设置元表(metatable) - **getmetatable(table)**: 返回对象的元表(metatable)。 #### 元方法 + **__index** - 当访问一个table的字段时,如果table有这个字段,则直接返回对应的值; - 找不到该字段,则判断该表是否有元表,没有元表返回nil,有元表则继续; - 判断元表有没有__index方法,如果__index方法为nil,则返回nil;如果__index方法是一个表,则重复上述步骤;如果__index方法是一个函数,则返回该函数的返回值。 + **__newindex** __newindex元方法与__index类似,__newindex用于更新table中的数据,而__index用于查询table中的数据 + **__tostring** tostring会调用 + **__call** table作为方法调用时会调用该元方法。 ``` lua --[[lua表,...
### 概述 + 问题1: 源站响应慢,当客户端超时过早的关闭连接时,nginx会打印一条499的access日志。这个时候我们需要排查到底是和上游的tcp握手包丢了,还是源站响应慢。`$upstream_connect_time`能说明问题么。 + 问题2: nginx返回502,到底是nginx没连上后端,还是后端返回的。`$upstream_status`能说明问题么。 对于问题1的这两种情况error log都不会记录错误信息。 此时我们一般会看access日志的这个变量`$upstream_connect_time`,文档表述: ``` keeps time spent on establishing a connection with the upstream server (1.9.1) ... ``` 建立起握手所消耗的时长。如果是1.15.7之前的nginx版本,那么你会发现日志是一个'-'。根据文档说明应该是没连上源站服务器。 其实不是这样的。 对于问题2`$upstream_status`是保存了从上游响应的状态码,但是502不一定是上游返回的状态码,可能是没有活着的上游。 ```...
lua中table是简直是万能的。 lua table构造式,可以实现有趣的用法,先来看个简单的例子: ```lua local authors = {} function Entry(e) authors[e.author] = true end -- data began Entry { author = "foo" } Entry { author = "bar" } --...
### 记录一些开发过程容易犯错的地方。 1. 和其他语言不通lua的下标是从1开始的。 2. lua中只有false和nil是假。0也是真。因此`if #str then`这样的判断没有意义。 3. #tab 的操作,tab中不能有空洞。例如。` a = {1,2,3,4,5}; a[2]=nil; #a ` 是1而不是4. 4. tab的空洞还影响unpack、ipairs、select('#', tab)。 5. xpcall 在lua5.1和lua5.3、luajit不一致。 ```lua do local xpcall_52 = xpcall(...
迭代器(iterator)是一种数据结构,能够遍历集合的每个元素。在lua中是一种支持指针类型的结构。 lua中熟知的迭代器有`pairs`和`ipairs`。通常配合泛型`for`同时使用。 例如: ```lua a = {3, 1, 12} for i, v in ipairs(a) do print(i, v) end ``` 我们自己也可以实现一个类似于ipairs的功能 ```lua function iter (a, i) i = i + 1...
### 概述 要看懂openssl的代码,首先得了解openssl的作用和openssl的协议以及[tls握手](https://www.cloudflare.com/zh-cn/learning/ssl/what-happens-in-a-tls-handshake/)。 第一步,client向server发送 协议版本号、生成的随机数(client_random)、支持的加密方法。 第二步,server返回 确认双方使用的加密方法、数字证书、以及一个服务器生成的随机数(server_random)。 第三步,client先验证数字证书有效,然后生成一个新的随机数(pre_random),并使用数字证书中的公钥,加密这个随机数,发给server。 第四步,server使用自己的私钥,解密client发来的随机数(pre_random)。 第五步,client和server根据约定的加密方法,使用前面的三个随机数,生成"对话密钥"(session key),用来加密接下来的整个对话过程。 第一步,client向server发送 协议版本号、生成的随机数(client_random)、支持的加密方法。 第二步,server返回 确认双方使用的加密方法、数字证书、以及一个服务器生成的随机数(server_random)。 + 同时服务器利用私钥将 client_random,server_random,server_params 签名,生成服务器签名。然后将签名和 server_params 也发送给客户端(这里的server_params为DH算法所需参数)。 第三步,client先验证数字证书和签名有效,将client_params发给server(这里的client_params 为DH算法所需参数)。 第四步,client和server都有 client_params、server_params 两个参数。 + client和server通过这两个DH参数就能计算出 pre_random。 第五步,client和server根据约定的加密方法,使用前面的三个随机数,生成"对话密钥"(session...
统计,记载openresty开发过程碰到的问题 ### 问题 1 致循环引用错误,一般情况是lua脚本语法有问题,或者是找不到某个文件导致。 2 table传引用导致诡异问题出现。 3 ngx.shared.DICT.incr val要用tonumber()显示的转换。否则会包not a number。 4 lua_use_default_type 坑。因后端没有返回content-type,OpenResty使用默认的content-type导致浏览器解析有问题。 ### rewrite导致set变量的坑 #### 问题描述 + 在server块,用`set`指令设置了一个变量。例如:`set $cache "off"`; + 在location的access阶段用lua脚本根据配置设置该变量。例如:`ngx.var.cache = "on"` + 在location中又添加了`mirror`指令。导致log阶段取到的变量还是off。例如:`ngx.log(ngx.INFO, ngx.var.cache)`...
### 概述 业务上很多特殊的需求还是需要修改nginx的代码来实现,而这些特殊的需求又不通用,nginx上根本不会支持。 ### patch + patch 1: 缓存文件添加前缀。 修改nginx代码在`proxy_cache_path` 添加`prefix=$var` 支持缓存文件后缀名。 配置实例: ```nginx proxy_cache_path ./cache levels=1:2 prefix=$host keys_zone=test:10m max_size=1g; ``` 测试: ```sh ./cache/e/0b/www.test.comd0431adbaa72e1b38e0884b71c9d30be ``` ```diff diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h...
### 概述 本篇只分析epoll相关的网络事件。涉及到epoll的EPOLLIN|EPOLLOUT|EPOLLET这几个事件。 epoll事件触发分为水平触发和边沿触发,水平触发是缓存区有内容时,或缓存区可写时会一直触发。而边沿触发是缓存区从无内容变成有内容,或缓存区从不可写变成可写时触发一次。 + 相关常数 EPOLLIN 可读,EPOLLOUT可写,EPOLLET边沿触发。 ### 代码分析 + 首先会调用`ngx_add_event(rev, NGX_READ_EVENT, 0)` 把监听fd的可读事件添加到epoll中,flags为0,epoll默认是水平触发。ngx_add_event 是个函数指针,指向ngx_epoll_add_event函数。 + 当有连接建立时,nginx调用epoll_wait监听到上述添加的事件可读,最终调用该可读事件的回调函数ngx_event_accept。 + ngx_event_accept函数会调用accept接受连接,调用 ls->handler(c); 该函数为ngx_http_init_connection,在ngx_http_block中赋的值。该函数对刚建立连接fd的可读可写事件的回调函数进行赋值,分别是ngx_http_wait_request_handler和ngx_http_empty_handler,然后调用ngx_add_timer添加超时定时,调用ngx_handle_read_event把可读事件添加到epoll中。 + 处理可读事件时,会一直调用ngx_http_read_request_header,该函数又会调用ngx_unix_recv函数,该函数有可读事件会一直读,直到读到没有缓存区为空直到返回eagain才把可读事件的ready赋0。 ### nginx 处理惊群 + 描述 自从支持了reuseport后,nginx采用锁方式解决惊群已经不再使用了。支持了reuseport后,Linux已经在内核层面解决了惊群问题。请参考[《nginx...
### 概述 [http_proxy](http://nginx.org/en/docs/http/ngx_http_proxy_module.html)提供了缓存功能,开源版本并没有提供缓存删除。第三方的[http_cache_purge](https://github.com/FRiCKLE/ngx_cache_purge)提供了缓存删除功能,该模块提供了2种删除缓存的配置,一种是: `proxy_cache_purge on|off| [from all| [.. ]]`。另一种是:`proxy_cache_purge zone_name key`。 ```nginx http { proxy_cache_path /tmp/cache levels=1:2 keys_zone=test_cache:10m max_size=1g; proxy_cache_valid 200 302 30m; proxy_cache_valid 301 404 1m; ...... server {...