真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

SkyDNS工作原理是什么

這篇文章主要講解了“SkyDNS工作原理是什么”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“SkyDNS工作原理是什么”吧!

創(chuàng)新互聯(lián)專業(yè)網(wǎng)站設(shè)計制作、做網(wǎng)站,集網(wǎng)站策劃、網(wǎng)站設(shè)計、網(wǎng)站制作于一體,網(wǎng)站seo、網(wǎng)站優(yōu)化、網(wǎng)站營銷、軟文平臺等專業(yè)人才根據(jù)搜索規(guī)律編程設(shè)計,讓網(wǎng)站在運行后,在搜索中有好的表現(xiàn),專業(yè)設(shè)計制作為您帶來效益的網(wǎng)站!讓網(wǎng)站建設(shè)為您創(chuàng)造效益。

SkyDNS2是SkyDNS Version 2.x的統(tǒng)稱,其官方文檔只有README.md,網(wǎng)上能找到的資料也不多,因此需要我們自行對代碼進行一定的分析,才能對其有更好的理解,這就是本文的工作,通過走讀SkyDNS的代碼,了解其內(nèi)部架構(gòu)及其工作原理。

SkyDNS工作原理

SkyDNS Server的工作,依賴后端Key-Value存儲的支持。當前支持etcd或etcd3作為Backend(架構(gòu)圖中藍色部分),為SkyDNS提供配置和數(shù)據(jù)的管理。

通過環(huán)境變量ETCD_MACHINES進行etcd cluster的配置,如果Backend為etcd3,還需要設(shè)置etcd中/v2/keys//skydns/config/etcd3為true。SkyDNS中有etcd client模塊,負責與ETCD_MACHINES的通信。

SkyDNS主要對應(yīng)的etcd key path如下:

/v2/keys/skydns/config
/v2/keys/skydns/local/skydns/east/production/rails
/v2/keys/skydns/local/skydns/dns/stub
/v2/keys/skydns/local/skydns/...

通過如下環(huán)境變量的配置,支持prometheus監(jiān)控(架構(gòu)圖中棕色部分)。如果想disable prometheus監(jiān)控,則配置環(huán)境變量PROMETHEUS_PORT的值為0即可。

Port      = os.Getenv("PROMETHEUS_PORT")
Path      = envOrDefault("PROMETHEUS_PATH", "/metrics")
Namespace = envOrDefault("PROMETHEUS_NAMESPACE", "skydns")
Subsystem = envOrDefault("PROMETHEUS_SUBSYSTEM", "skydns")

如果/v2/keys/skydns/config/nameservers有值,則SkyDNS解析不了的Domain,會forward到對應(yīng)的這些IP:Port構(gòu)成的nameservers,由它們進行解析(架構(gòu)圖中綠色部分)。

參考官方文檔https://github.com/skynetservices/skydns/blob/master/README.md完成參數(shù)配置后,便可啟動SkyDNS。

SkyDNS Server的啟動過程如下:

  • 創(chuàng)建etcd client對象;

  • dns_addr 和 nameservers參數(shù)合法性檢查;

  • 加載啟動參數(shù)到etcd,覆蓋/v2/keys/skydns/config中原有數(shù)據(jù);

  • 配置SkyDNS Server參數(shù)的default值,并創(chuàng)建SkyDNS server對象;

  • 去etcd中加載.../dns/stub//xx數(shù)據(jù)作為server的stub zones數(shù)據(jù),并啟動對.../dns/stub/的watcher,一旦有數(shù)據(jù)更新,就加載到server的stub zones數(shù)據(jù)中;

  • 注冊SkyDNS metrics到prometheus;

  • 然后在/v2/keys/skydns/config/dns_addr配置的interface和port上開啟tcp/udp監(jiān)聽服務(wù)并block住,由此開始提供DSN服務(wù)。

在github.com/skynetservices/skydns/server/server.go中的ServeDNS方法覆蓋了miekg/dns/server中的ServeMux.ServeDNS方法,由自實現(xiàn)的ServeDNS提供來處理DNS client的請求。

github.com/skynetservices/skydns/server/server.go

// ServeDNS is the handler for DNS requests, responsible for parsing DNS request, possibly forwarding
// it to a real dns server and returning a response.
func (s *server) ServeDNS(w dns.ResponseWriter, req *dns.Msg) {
	...
	// Check cache first.
	m1 := s.rcache.Hit(q, dnssec, tcp, m.Id)
	if m1 != nil {
		...
		// Still round-robin even with hits from the cache.
		// Only shuffle A and AAAA records with each other.
		if q.Qtype == dns.TypeA || q.Qtype == dns.TypeAAAA {
			s.RoundRobin(m1.Answer)
		}

		...
		return
	}

	for zone, ns := range *s.config.stub {
		if strings.HasSuffix(name, "." + zone) || name == zone {
			metrics.ReportRequestCount(req, metrics.Stub)

			resp := s.ServeDNSStubForward(w, req, ns)
			if resp != nil {
				s.rcache.InsertMessage(cache.Key(q, dnssec, tcp), resp)
			}

			metrics.ReportDuration(resp, start, metrics.Stub)
			metrics.ReportErrorCount(resp, metrics.Stub)
			return
		}
	}
	...
	
	if name == s.config.Domain {
		if q.Qtype == dns.TypeSOA {
			m.Answer = []dns.RR{s.NewSOA()}
			return
		}
		if q.Qtype == dns.TypeDNSKEY {
			if s.config.PubKey != nil {
				m.Answer = []dns.RR{s.config.PubKey}
				return
			}
		}
	}
	if q.Qclass == dns.ClassCHAOS {
		if q.Qtype == dns.TypeTXT {
			switch name {
			case "authors.bind.":
				fallthrough
			case s.config.Domain:
				hdr := dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassCHAOS, Ttl: 0}
				authors := []string{"Erik St. Martin", "Brian Ketelsen", "Miek Gieben", "Michael Crosby"}
				for _, a := range authors {
					m.Answer = append(m.Answer, &dns.TXT{Hdr: hdr, Txt: []string{a}})
				}
				for j := 0; j < len(authors)*(int(dns.Id())%4+1); j++ {
					q := int(dns.Id()) % len(authors)
					p := int(dns.Id()) % len(authors)
					if q == p {
						p = (p + 1) % len(authors)
					}
					m.Answer[q], m.Answer[p] = m.Answer[p], m.Answer[q]
				}
				return
			case "version.bind.":
				fallthrough
			case "version.server.":
				hdr := dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassCHAOS, Ttl: 0}
				m.Answer = []dns.RR{&dns.TXT{Hdr: hdr, Txt: []string{Version}}}
				return
			case "hostname.bind.":
				fallthrough
			case "id.server.":
				// TODO(miek): machine name to return
				hdr := dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassCHAOS, Ttl: 0}
				m.Answer = []dns.RR{&dns.TXT{Hdr: hdr, Txt: []string{"localhost"}}}
				return
			}
		}
		// still here, fail
		m.SetReply(req)
		m.SetRcode(req, dns.RcodeServerFailure)
		return
	}

	switch q.Qtype {
	case dns.TypeNS:
		if name != s.config.Domain {
			break
		}
		// Lookup s.config.DnsDomain
		records, extra, err := s.NSRecords(q, s.config.dnsDomain)
		if isEtcdnameError(err, s) {
			m = s.NameError(req)
			return
		}
		m.Answer = append(m.Answer, records...)
		m.Extra = append(m.Extra, extra...)
	case dns.TypeA, dns.TypeAAAA:
		records, err := s.AddressRecords(q, name, nil, bufsize, dnssec, false)
		if isEtcdNameError(err, s) {
			m = s.NameError(req)
			return
		}
		m.Answer = append(m.Answer, records...)
	case dns.TypeTXT:
		records, err := s.TXTRecords(q, name)
		if isEtcdNameError(err, s) {
			m = s.NameError(req)
			return
		}
		m.Answer = append(m.Answer, records...)
	case dns.TypeCNAME:
		records, err := s.CNAMERecords(q, name)
		if isEtcdNameError(err, s) {
			m = s.NameError(req)
			return
		}
		m.Answer = append(m.Answer, records...)
	case dns.TypeMX:
		records, extra, err := s.MXRecords(q, name, bufsize, dnssec)
		if isEtcdNameError(err, s) {
			m = s.NameError(req)
			return
		}
		m.Answer = append(m.Answer, records...)
		m.Extra = append(m.Extra, extra...)
	default:
		fallthrough // also catch other types, so that they return NODATA
	case dns.TypeSRV:
		records, extra, err := s.SRVRecords(q, name, bufsize, dnssec)
		if err != nil {
			if isEtcdNameError(err, s) {
				m = s.NameError(req)
				return
			}
			logf("got error from backend: %s", err)
			if q.Qtype == dns.TypeSRV { // Otherwise NODATA
				m = s.ServerFailure(req)
				return
			}
		}
		// if we are here again, check the types, because an answer may only
		// be given for SRV. All other types should return NODATA, the
		// NXDOMAIN part is handled in the above code. TODO(miek): yes this
		// can be done in a more elegant manor.
		if q.Qtype == dns.TypeSRV {
			m.Answer = append(m.Answer, records...)
			m.Extra = append(m.Extra, extra...)
		}
	}

	if len(m.Answer) == 0 { // NODATA response
		m.Ns = []dns.RR{s.NewSOA()}
		m.Ns[0].Header().Ttl = s.config.MinTtl
	}
}

上面代碼邏輯比較復(fù)雜,細節(jié)上需要你慢慢去理解,簡短的可以總結(jié)如下:

  • 如架構(gòu)圖中標注的線路1:如果在SkyDNS維護的cache中找到對應(yīng)Msg,則從cache中讀取并返回Msg給DNS client;

  • 如架構(gòu)圖中標注的線路2:如果在cache中沒有對應(yīng)的記錄,并且是需要DNS forward的場景(比如name匹配到stub zones等),則將請求forward到對應(yīng)的DNS servers進行處理;

  • 如架構(gòu)圖中標注的線路3:如果在cache中沒有對應(yīng)的記錄,并且Question Type為A/AAAA,SRV等類型時,就通過etcd client去etcd cluster中獲取對應(yīng)的Rule,并構(gòu)造Msg返回。

感謝各位的閱讀,以上就是“SkyDNS工作原理是什么”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對SkyDNS工作原理是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!


新聞名稱:SkyDNS工作原理是什么
網(wǎng)站URL:http://weahome.cn/article/psjgdg.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部