版权声明:本文为博主原创文章,未经博主允许不得转载
DNS缓存
DNS的缓存策略,tcp连接优化处理
看了一篇DNS缓存的博客,想到我们自己的项目中也有和这个机制,于是整理了一下
大神博客的核心思路:
- 降低DNS请求带来的延迟
- 客户端app的请求第一步都是DNS解析,直接跳过DNS解析这一步,能提升网络性能
- 预防DNS劫持
- DNS劫持指的是改变DNS请求的返回结果,将目的ip指向另一个地址。客户端自己做DNS与ip地址的映射就跨过了解析,让劫持者无从下手。
- 服务器动态部署(这个如果是直接连IP的话,好像用不到)
设计自己的DNS映射机制
- 一个打包到app包里面的默认映射文件,这样可以避免第一次去服务器取配置文件带来的延迟。
- 有一个定时器能每隔一段时间从服务器获取最新的映射,并覆盖本地。
- 每次取到最新的映射文件之后,同时把上一次的映射文件保存起来作为替补,一旦出现线上配置失误不至于导致请求无法处理。
- 如果映射文件不能处理域名,要能回滚使用默认的DNS解析服务。
- 如果一个映射过后的ip持续导致请求失败,应该能从机制上保证这个ip地址不再使用。也就是需要一个无效映射淘汰机制。
- 无效的ip地址能及时上报到服务器,及时发现问题更新映射文件。
我们项目中的IP缓存策略是:
- 第一次连接,首先连接默认内置IP,同时另起线程对内置域名进行DNS解析,解析结果存入DNSPool,并且进行连接(最多6个); 当有IP连接上后断开其他连接
- 连上服务器后下发一些IPs,存入serverPool (或者服务器IP有变,则下发临时IP,存入tempPool,为了防止某些情况下IP变化连接不上)
- 第二次及之后连接,从serverPool中取最多6个IP出来进行连接(带上版本号),同时另起线程对内置域名进行DNS解析,解析结果存入DNSPool, 并且进行连接(最多6个);同时对比serverPool,将新解析的IP加入serverPool;
- 当有IP连上服务器后,断开其他连接;服务器根据serverPool的版本号判断是否下发IPs存入serverPool (或者服务器IP有变,则下发临时IP,存入tempPool,为了防止某些情况下IP变化连接不上)
- 建联时每次都会去DNS解析域名,结果存入DNSPool(最短时间间隔60s)
注:
- serverPool:默认IP+服务器下发IP池
- DNSPool:DNS解析IP池
- tempPool:服务器下发临时IP池
其他
ipv4 vs ipv6
ipv4是互联网协议(Internet Protocol,IP)的第四版
ipv6用于替代现行版本IP协议(IPv4)的下一代IP协议
ssl:数据加密协议,ipv6需要支持
DNS解析:域名解析
IPv4中使用gethostbyname()函数完成主机名到地址解析,这个函数仅仅支持IPv4,且不允许调用者指定所需地址类型的任何信息,返回的结构只包含了用于存储IPv4地址的空间。
IPv6中引入了getaddrinfo()的新API,它是协议无关的,既可用于IPv4也可用于IPv6。getaddrinfo函数能够处理名字到地址以及服务到端口这两种转换,返回的是一个addrinfo的结构(列表)指针而不是一个地址清单。这些addrinfo结构随后可由套接口函数直接使用。如此以来,getaddrinfo函数把协议相关性安全隐藏在这个库函数内部。应用程序只要处理由getaddrinfo函数填写的套接口地址结构。
代码:
+ (NSArray *)syncGetaddrinfoWithDomain:(NSString *)domain
{
if (domain.length == 0) {
return nil;
}
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_INET;
hints.ai_protocol = IPPROTO_TCP;
struct addrinfo *addrs, *addr;
int getResult = getaddrinfo([domain UTF8String], NULL, &hints, &addrs);
if (getResult || addrs == nil) {
NSLogToFile(@"Warn: DNS with domain:%@ failed:%d", domain, getResult);
return nil;
}
addr = addrs;
NSMutableArray *result = [NSMutableArray array];
for (addr = addrs; addr; addr = addr->ai_next) {
char host[NI_MAXHOST];
memset(host, 0, NI_MAXHOST);
getnameinfo(addr->ai_addr, addr->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
if (strlen(host) != 0) {
[result addObject:[NSString stringWithUTF8String:host]];
}
}
freeaddrinfo(addrs);
NSLogToFile(@"Info: DNS with domain:%@ -> %@", domain, result);
return result;
}