# 使用动态DNS来完成HTTP请求
其实针对大多应用场景,DNS是不会频繁变更的,使用nginx默认的resolver配置方式就能解决。
在奇虎360企业版的应用场景下,需要支持的系统众多:win、centos、ubuntu等,不同的操作系统获取dns的方法都不太一样。再加上我们使用docker,导致我们在容器内部获取dns变得更加难以准确。
如何能够让Nginx使用随时可以变化的DNS源,成为我们急待解决的问题。
当我们需要在某一个请求内部发起这样一个http查询,采用proxy_pass是不行的(依赖resolver的dns,如果dns有变化,必须要重新加载配置),并且由于proxy_pass不能直接设置keepconn,导致每次请求都是短链接,性能损失严重。
使用resty.http,目前这个库只支持ip:port的方式定义url,其内部实现并没有支持domain解析。resty.http是支持set_keepalive完成长连接,这样我们只需要让他支持dns解析就能有完美解决方案了。
~~~
local resolver = require "resty.dns.resolver"
local http = require "resty.http"
function get_domain_ip_by_dns( domain )
-- 这里写死了google的域名服务ip,要根据实际情况做调整(例如放到指定配置或数据库中)
local dns = "8.8.8.8"
local r, err = resolver:new{
nameservers = {dns, {dns, 53} },
retrans = 5, -- 5 retransmissions on receive timeout
timeout = 2000, -- 2 sec
}
if not r then
return nil, "failed to instantiate the resolver: " .. err
end
local answers, err = r:query(domain)
if not answers then
return nil, "failed to query the DNS server: " .. err
end
if answers.errcode then
return nil, "server returned error code: " .. answers.errcode .. ": " .. answers.errstr
end
for i, ans in ipairs(answers) do
if ans.address then
return ans.address
end
end
return nil, "not founded"
end
function http_request_with_dns( url, param )
-- get domain
local domain = ngx.re.match(url, [[//([\S]+?)/]])
domain = (domain and 1 == #domain and domain[1]) or nil
if not domain then
ngx.log(ngx.ERR, "get the domain fail from url:", url)
return {status=ngx.HTTP_BAD_REQUEST}
end
-- add param
if not param.headers then
param.headers = {}
end
param.headers.Host = domain
-- get domain's ip
local domain_ip, err = get_domain_ip_by_dns(domain)
if not domain_ip then
ngx.log(ngx.ERR, "get the domain[", domain ,"] ip by dns failed:", err)
return {status=ngx.HTTP_SERVICE_UNAVAILABLE}
end
-- http request
local httpc = http.new()
local temp_url = ngx.re.gsub(url, "//"..domain.."/", string.format("//%s/", domain_ip))
local res, err = httpc:request_uri(temp_url, param)
if err then
return {status=ngx.HTTP_SERVICE_UNAVAILABLE}
end
-- httpc:request_uri 内部已经调用了keepalive,默认支持长连接
-- httpc:set_keepalive(1000, 100)
return res
end
~~~
动态DNS,域名访问,长连接,这些都具备了,貌似可以安稳一下。在压力测试中发现这里面有个机制不太好,就是对于指定域名解析,每次都要和DNS服务回话询问IP地址,实际上这是不需要的。普通的浏览器,都会对DNS的结果进行一定的缓存,那么这里也必须要使用了。
对于缓存实现代码,请参考ngx_lua相关章节,肯定会有惊喜等着你挖掘碰撞。
- 序
- Lua简介
- Lua环境搭建
- 基础数据类型
- 表达式
- 控制结构
- if/else
- while
- repeat
- 控制结构for的使用
- break,return
- Lua函数
- 函数的定义
- 函数的参数
- 函数的返回值
- 函数回调
- 模块
- String库
- Table库
- 日期时间函数
- 数学库函数
- 文件操作
- 元表
- 面向对象编程
- FFI
- LuaRestyRedisLibrary
- select+set_keepalive组合操作引起的数据读写错误
- redis接口的二次封装(简化建连、拆连等细节)
- redis接口的二次封装(发布订阅)
- pipeline压缩请求数量
- script压缩复杂请求
- LuaCjsonLibrary
- json解析的异常捕获
- 稀疏数组
- 空table编码为array还是object
- 跨平台的库选择
- PostgresNginxModule
- 调用方式简介
- 不支持事务
- 超时
- 健康监测
- SQL注入
- LuaNginxModule
- 执行阶段概念
- 正确的记录日志
- 热装载代码
- 阻塞操作
- 缓存
- sleep
- 定时任务
- 禁止某些终端访问
- 请求返回后继续执行
- 调试
- 调用其他C函数动态库
- 我的lua代码需要调优么
- 变量的共享范围
- 动态限速
- shared.dict 非队列性质
- 如何添加自己的lua api
- 正确使用长链接
- 如何引用第三方resty库
- 使用动态DNS来完成HTTP请求
- 缓存失效风暴
- Lua
- 下标从1开始
- 局部变量
- 判断数组大小
- 非空判断
- 正则表达式
- 不用标准库
- 虚变量
- 函数在调用代码前定义
- 抵制使用module()函数来定义Lua模块
- 点号与冒号操作符的区别
- 测试
- 单元测试
- API测试
- 性能测试
- 持续集成
- 灰度发布
- web服务
- API的设计
- 数据合法性检测
- 协议无痛升级
- 代码规范
- 连接池
- c10k编程
- TIME_WAIT问题
- 与Docker使用的网络瓶颈
- 火焰图
- 什么时候使用
- 显示的是什么
- 如何安装火焰图生成工具
- 如何定位问题