觀察 Round-Robin DNS 查詢結果變化
0 |
Round-Robin DNS (DNS 輪循、循環 DNS) 是非常古老的負載平衡手法,其原理是 DNS 伺服器回應 DNS 請求時,返回結果來自一長串 IP 位址清單,並在每次回應時抽換 IP 組合跟掉換 IP 順序,一般來說,客戶端會採用回應結果的第一個 IP,如此,要連上 www.xxx.yyy 的不同客戶端便會導向不同 IP 連到不同主機,達到分散流量及工作負載的效果。
雖然這種做法無法平均分配負載(將流量導向空閒主機)、不會避開故障中的伺服器,並可能因客戶端快取減弱效果,但因為容易實現,至今仍普遍使用。(延伸閱讀:現代 CDN 會使用 BGP Anycast 實現負載平衡,Internet 跟你想的不一樣:IP 地址不是唯一,有許多相同 IP 的主機散落各地)
以微軟的 login.microsoftonline.com 為例,nslookup 可得到 8 個 IPv4 地址,反覆查詢,IP 項目及順序會改變:
好奇心起:這個 IP 清單包含多少個不同 IP?每次查詢 IP 的變化有特殊規律嗎?
做個實驗試試,我寫了以下 PowerShell 從 nslookup 輸出擷取 IPv4 地址,10 秒查一次。
for ($i = 0; $i -lt 128; $i++) {
$capture = $false
$ips = @()
. nslookup.exe login.microsoftonline.com 8.8.8.8 | ForEach-Object {
if ($_ -match 'Addresses') {
$capture = $true
}
elseif ($capture -and $_ -match '(\d+\.\d+\.\d+\.\d+)') {
$ips += $matches[1]
}
}
Write-Output ($ips -join ',')
Start-Sleep -Seconds 10
}
.\run-100-times-dns.ps1 | Out-File -FilePath 'dns-results.txt'
將執行結果輸出到 dns-results.txt。有趣的是,「未經授權的回答:」是透過 stderr 輸出,不會寫入檔案而是顯示在螢幕上。
然後我用 Vue 寫了個簡單查詢,方便觀察各 IP 出現次數、順序。線上展示
由結果可知,login.microsoftonline.com 背後共有 20 個 IP,每次出現 8 個 128 次總數 1024,1024 / 20 = 理論上每個 IP 會出現 51.2 次,接近實測的數字。而順序分佈也呈現隨機。點選最上方 IP [1] 可觀察該 IP 出現在哪些資料列,點選列號 [2] 可觀察相同 IP 組合重複出現的位置。依觀察結果,相同 IP 組合出現次數介於 1 到 7 次,而且偏集中,前後很少超過五分鐘(每列相隔十秒,也就是序號差小於 30)。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Round-Robin DNS Test</title>
<script src="https://unpkg.com/vue@3"></script>
<style>
body {
font-family: Arial, Helvetica, sans-serif; font-size: 9pt;
}
.iplist {
display: flex; flex-direction: row; flex-wrap: wrap;
}
.iplist>span {
margin-right: 2px; padding: 2px; border: 1px solid #ccc;
width: 120px; text-align: center;
}
table {
margin-top: 12px; border-collapse: collapse;
}
tr:nth-child(odd) {
background-color: #eee;
}
td {
border: 1px solid #ccc; padding: 4px;
}
td.sn {
text-align: right;
}
.focus {
text-shadow: 1px 1px 2px black; font-weight: bolder;
background-color: black!important;
color: yellow!important;
}
.link {
cursor: pointer;
}
#app {
width: 800px;
}
.dc-0 { color:#e6194B; } .dbc-0 { color:#ffffff; background-color:#e6194Ba0; }
.dc-1 { color:#3cb44b; } .dbc-1 { color:#ffffff; background-color:#3cb44ba0; }
/* ... 省略 ... */
.dc-20 { color:#ffffff; } .dbc-20 { color:#000000; background-color:#ffffffa0; }
.dc-21 { color:#000000; } .dbc-21 { color:#ffffff; background-color:#000000a0; }
</style>
<script type="application/x-data" id="data">
40.126.38.19,20.190.166.68,20.190.166.66,20.190.166.132,20.190.166.67,40.126.38.22,20.190.166.131,40.126.38.20
20.190.141.33,20.190.141.32,20.190.141.39,20.190.141.38,20.190.141.37,20.190.141.35,40.126.13.8,40.126.13.9
... 省略 ...
40.126.13.9,20.190.141.38,40.126.13.8,20.190.141.33,20.190.141.35,20.190.141.39,20.190.141.32,20.190.141.37
</script>
</head>
<body>
<div id="app">
<div class="iplist">
<span v-for="ip in list" @click="focusIp = ip" class="link"
:class="css(ip)">{{ip}} ({{counts[ip]}})</span>
</div>
<table>
<tr v-for="(line,idx) in data" >
<td class="sn link" @click="focusLine = line" :class="{'focus':focusLine == line}">
{{idx+1}}. ({{dupLineCount[line]}})
</td>
<td v-for="ip in line.split(',')" :class="css(ip)">{{ip}}</td>
</tr>
</table>
</div>
<script>
const data = [];
const ipChk = {};
const counts = {};
const dupLineCount = {};
let c = 0;
document.head.querySelector('script[id=data]').innerText.split('\n').forEach(function (line) {
line = line.trim();
if (!line) return;
if (line in dupLineCount) dupLineCount[line]++;
else dupLineCount[line] = 1;
var ips = line.split(',');
ips.forEach(function (ip) {
if (!(ip in ipChk)) { ipChk[ip] = c++; counts[ip] = 0; }
else counts[ip]++;
});
data.push(line);
});
const ips = Object.keys(ipChk);
ips.sort();
const app = Vue.createApp({
data: function () {
return {
data: data,
list: ips,
counts: counts,
focusLine: '',
dupLineCount: dupLineCount,
focusIp: ''
};
},
methods: {
css: function (ip) {
return (this.focusIp == ip ? 'focus ' : '') +
'dbc-' + (ipChk[ip] % 22);
}
}
});
app.mount('#app');
</script>
</body>
</html>
就醬,我又完成一次無聊的實驗,累積一些 Coding 經驗。
A experiment to observe how round-robin DNS provides different IP addresses.
Comments
Be the first to post a comment