目前昨天查乙個線上問題:「」dns伺服器在我們的裝置, 有大量的終端到裝置上請求解析網域名稱,但是一直是單執行緒,dns報文處理不過來」, 然而裝置是多核,dns伺服器一直不能利用多核資源,所以能不能使用多執行緒進行處理呢?
udp不像tcp那樣,udp沒有連線的概念,也就是沒有通過建立多個連線來提高對dns伺服器併發訪問,然而在多核環境下那就只能通過多執行緒來訪問乙個共享的udp socket,但是還是乙個socket , 會涉及到多執行緒搶占資源問題。
來看一下核心協議棧udp收到包**:根據以前分析tcpip協議棧文章可以知道,報文在核心協議棧流程大約如下:
也就是 報文送到那個socket是由__udp4_lib_lookup這個函式做出選擇, 選擇的依據是 ip 埠號 介面來進行處理選擇對應的socket,對於
dhcp dns伺服器來說一般不會繫結介面,所以一般就是 設定ip udp.port, 所以核心選擇socket的時候一般也是通過對比ip port來查詢。通過找出匹配層度最高的socket作為收包sk。
如果要是允許有多個socket呢??
那麼不就是可以通過輪詢選擇或者hash選擇出對應的socket 嗎!!!!!!!!所以在linux 3.9核心版本後面增加reuseport,允許多個socket繫結同乙個ip port, 通過hash雜湊在桶裡面,
socket bind ip port時 會呼叫get_port 計算是否存在ip port存在衝突, linux 3.9patch中對hash 以及計算方式加入reuseport,可以允許多個socket bind同樣的ip port。
同乙個客戶端的資料總是分配給同乙個 udp_sock。so!! 在寫 udp server 的時候,為了提高處理能力,可以起多個執行緒,每個執行緒讀寫自己的 udp socket
順便看一看udp 怎樣查詢port:
int udp_v4_get_port(struct sock *sk, unsigned short snum)
udp 對於porttable維護乙個是一port 進行hash 乙個是以sip +port(port=0) 進行hash。
struct udp_sock
udp 協議的主要資料結構是兩張 hash 表,指向 udp 協議控制塊 struct udp_sock。其中 hash1 以 port 為 key,
hash2 以 ip+port (port=0)為 key 但是後續會使用udp_portaddr_hash ^port 進行hash查詢,實際上也就是ip+port表 ;
所以一開始看的udp_portaddr_hash 是以ip+port=0 進行hash計算有點懵逼!!!
1 int udp_lib_get_port(struct sock *sk, unsigned short snum,2 int (*saddr_comp)(const struct sock *sk1,
3 const struct sock *sk2,
4bool match_wildcard),
5unsigned int hash2_nulladdr)
6 else
72if
(exist)
73goto fail_unlock;
74else
75goto found;76}
77scan_primary_hash://scan_primary_hash**段是在hash表的hslot項中查詢,只有當在hash2中查詢更費時時才會執行
78if
(udp_lib_lport_inuse(net, snum, hslot, null, sk,
79saddr_comp, 0))
80goto fail_unlock;81}
82found://執行sk的插入操作
83 inet_sk(sk)->inet_num =snum;
84 udp_sk(sk)->udp_port_hash =snum;
85 udp_sk(sk)->udp_portaddr_hash ^=snum;
86if
(sk_unhashed(sk))
9495 sk_add_node_rcu(sk, &hslot->head);
96 hslot->count++;
97 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
9899 hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash);
100 spin_lock(&hslot2->lock);
101if (is_enabled(config_ipv6) && sk->sk_reuseport &&
102 sk->sk_family ==af_inet6)
103 hlist_add_tail_rcu(&udp_sk(sk)->udp_portaddr_node,
104 &hslot2->head);
105else
106 hlist_add_head_rcu(&udp_sk(sk)->udp_portaddr_node,
107 &hslot2->head);
108 hslot2->count++;
109 spin_unlock(&hslot2->lock);
110}
111sock_set_flag(sk, sock_rcu_free);
112 error =0;
113fail_unlock:
114 spin_unlock_bh(&hslot->lock);
115fail:
116return
error;
117 }
如果snum==0,即沒有繫結本地埠,此時執行if部分**段,這種情況一般發生在客戶端使用socket,此時核心會為它選擇乙個未使用的埠:
udptable中的hash公司為 jhash_1word((__force u32)saddr, net_hash_mix(net)) ^ port------>(num + net_hash_mix(net)) & mask簡寫一下, net_hash_mix
(net)返回為0
所以大約就是sip^port; 具體就不細看hash函式了。也許不是這樣的。。。。
if (!snum) while迴圈的判斷條件snum!=first和snum+=rand一起保證了所有雜湊到hslot的埠號都會被遍歷到。如果找到了可用埠號,即跳出,執行插入sk的操作,否則++first,
查詢下乙個鍵值,直到fisrt==last,表明所有鍵值都已輪循一遍,仍沒有結果,則退出
*/do
while (snum !=first);
spin_unlock_bh(&hslot->lock
); }
while (++first !=last);
goto fail;
這部分是查詢網上分析結果!!還沒有仔細研究他的這個hash演算法
問題2:由於udp是包模式!! 每次只能copy乙個包!!!能不能copy多個!!!目前是可以的!!
可以使用recvmmsg來繼續降低系統呼叫的開銷。recvmmsg是乙個批量介面,它可以從socket裡一次讀出多個udp資料報,不像recvfrom那樣一次只能讀乙個。如果客戶端多、請求量大的話,recvmmsg的批量讀就很有優勢了。
就像hash表一樣存在衝突!!! 也就是讀取的多個包可能不是乙個客戶端發過來的資料!!!! 那怎樣區分多個客戶端發來的資料呢??在udp資料部分來區分??還是??
看核心**應該是通過rcvmmsg的控制資訊區分。。。。。讀取資料報文的時候也會帶上控制資訊這樣就可以知道對端了
對一次系統上線的思考 走出「舒適區」
今天,本來計畫是會對系統進行一次更新,將這上一周做的需求和修改的bug 發布出去,然後明天開始新的計畫,本來團隊已經對這個目標達成了一致,大家努力的測試,爭取今天能夠上線。後來有一位負責的同事說,今天要是上線更新不了,就明天吧,反正我們也沒有對需求方承諾具體的上線時間,明天再測試一天,沒問題在上線吧...
一次糟糕面試的思考
1.溝通原則之一,在溝通過程中發現對方問的問題有問題時,應在融洽的氣氛中當面指出,事後想找機會指出是無力的,並且可能沒有這樣的機會。但切記不要將這一切變成一場爭論。2.溝通原則之二,當對方與你針鋒相對時應怎麼辦呢?最明智的做法首先應指明這種狀態,希望雙方冷靜下來之後尋求新的溝通方式。若這種方法無法湊...
一次Debug過程的思考
前一段時間,部門接入了新業務,由於業務量小,架構非常簡單,採用了最簡單的lnmp架構,整個專案是交給乙個剛畢業的rd負責的,這是背景。上線前半天,服務平穩執行。下午的時候,開始收到大量報警 no host could be connected in the cluster。第一反應 mysql伺服器...