深信服一面总结
1 項目
項目是C++集群聊天服務器里面涉及到主要的技術棧有 nginx負載均衡器、基于redis的發布訂閱序列、muduo網絡庫(使用的時候特別的簡單,但是面試官一般會問它的底層代碼是怎么實現的,最主要的思想是epoll+線程池)、mysql、json序列化和反序列化
(1)怎么處理多個客戶端的連接
epoll去監聽客戶端的連接,當有多個客戶端到來之后條件變量利用廣播的方式去喚醒多個線程,線程來任務隊列取走任務。
線程池的創建
a 設置一個生產者消費者隊列作為臨界資源
b 初始話n個線程 并讓其運行起來,加鎖去隊列去任務運行(可以設置管理線程,根據任務的需要適時的增加和銷毀線程,增加和銷毀線程是有一定的步長,通過喚醒線程讓其自殺的方式去銷毀線程)
c 當任務隊列為空的時候,所有線程阻塞
d 當生產者隊列來了一個任務的時候,先對隊列加鎖,把任務掛在隊列上,然后使用條件變量去通知阻塞中的一個線程。
再來補充一下條件變量的知識貫通一下。
條件變量不是鎖,但是也可以使線程阻塞,經常與互斥鎖聯合使用,條件變量一般會做三件事情
a? 阻塞等待條件變量滿足
b 釋放已經掌握的互斥鎖相當于 pthread_mutex_unlock(&mutex)(a ,b兩步為一個原子操作)
c 當被喚醒,pthread_cond_wait函數返回時,解除阻塞并重新申請獲取互斥鎖 pthread_mutex_lock(&mutex);
條件變量可以減少生產者內部之間的競爭,減少資源的浪費。
(2)如果一個線程一直讀一個socket怎么辦
將多個socket保存下來,設置定時器,按照優先級去讀socket。
(3)nginx負載均衡策略
輪詢,ip_hash,ip_least.ip_weight;
企業常采用 ip_hash加一致性哈希算法的策略,每個客戶最好連接固定的服務器,每個服務器上有固定的緩存。一致性哈希算法目的就是某臺服務器掛掉之后盡量減少影響。
一致性哈希算法
如果是32位系統。用緩存數據除以2的32 次方取余數,通過這個余數把服務器映射到一個圓上,但是有可能會出現哈希傾斜的問題,針對此問題,最好虛擬出一些節點。使服務器均衡的映射到服務器。
nginx如何配置基于http或者基于tcp的負載均衡?
Nginx使用了一個新的stream模塊來實現TCP負載均衡,這個模塊,類似于http和mail模塊,允許我們配置一組監聽TCP連接的服務。允許你配置多個服務的TCP連接,通過在upstream的server組中配置proxy_pass指令。修改nginx.conf文件,在http模塊的統計目錄,添加一個stream模塊(和http等同級):
(4)redis的五大數據類型
(a)string :最基本的是 string 可以包含任何數據 比如 圖片或者序列化的對象。一個redis中字符串value最多可以是512M
? (b) hash 是一個string類型的field和value的映射表,hash特別適合與存儲對象
(c) list 常作為消息隊列使用
(d)set? ?適合去重 求交集
? (e)zset
redis是基于內存的操作,所以要比直接訪問數據庫快
Redis 持久化機制
Redis是一個支持持久化的內存數據庫,通過持久化機制把內存中的數據同步到硬盤文件來保證數據持久化。當Redis重啟后通過把硬盤文件重新加載到內存,就能達到恢復數據的目的。
實現:單獨創建fork()一個子進程,將當前父進程的數據庫數據復制到子進程的內存中,然后由子進程寫入到臨時文件中,持久化的過程結束了,再用這個臨時文件替換上次的快照文件,然后子進程退出,內存釋放。
RDB是redis默認的持久化方式。
AOF:redis會將每一個收到的寫命令都通過write函數追加到文件最后
當兩種方式同時開啟時,數據恢復redis會優先選擇AOF恢復。
緩存雪崩:原有緩存失效,新緩存未到,采用了相同的過期時間,再同一時刻出現大面積的緩存過期。
解決辦法:
(1)對數據進行加鎖或者隊列的方式保證不會有大量的線程對數據庫進行一次性讀寫
?(2)設置不同的緩存失效時間
緩存擊穿:
指一個key非常熱點,高并發集中訪問這個key,當這個key在失效瞬間,仍然持續的高并發訪問穿破緩存。
解決方法:
在訪問key之前,采用setnx 來設置另一個短期key來鎖住當前key的訪問,訪問結束后再刪除該短期key
關于redis的總結暫且寫到這里,還有好多關于redis的問題
2 linux
(1)linux常見的信號
Ctrl + c? → 2) SIGINT(終止/中斷)? "INT" ----Interrupt
Ctrl + z? → 20) SIGTSTP(暫停/停止)? "T" ----Terminal 終端。
?Ctrl + \? → 3) SIGQUIT(退出)
除0操作?? → 8) SIGFPE (浮點數例外)????? "F" -----float 浮點數。
非法訪問內存? → 11) SIGSEGV (段錯誤)
?總線錯誤? → 7) SIGBUS???
(2) linux查看進程占用內存的命令 top
(3)linux 查看cpu占用資源情況的命令 top
(4)僵尸進程:子進程退出 之后,還殘留一部分的PCB資源。父進程未對其進行回收
(5)僵尸進程存在的意義:父進程可以知道子進程結束時的狀態信息。
(6)linux 查看連接數
?a? 查看網絡狀態 netstat -an
b 查看 8080端口連接的情況? ?netstat -an|grep 80
c 統計80端口的連接數 netstat -nat | grep -i "80" |wc -l
d 統計httpd協議連接數?ps?-ef?|?grep httpd?|?wc?-l
e? 統計已連接上的,狀態為“established”??netstat?-na?|?grep ESTABLISHED?|?wc?-l
f? ?查出每個IP地址連接數
netstat?-na?|?grep ESTABLISHED?|?awk?'{print$5}'?|?awk?-F?:?'{print$1}'?|sort?|uniq?-c?|?sort?-r
(7) ping 百度發送icmp包
(8)路由是怎么傳遞的??
(9)TCP與UDP的區別
? TCP: 面向連接的可靠的數據包傳遞
數據穩定、速率穩定、流量穩定
使用場景:大文件,重要文件的傳輸
UDP :無連接的不可靠的報文傳遞;
效率高,速度快,不穩定
使用場景,對實時性要求比較高的,視頻會議和視頻電話。
3 C++
(1)map的底層是什么?為什么
map的底層是紅黑樹,為什么用紅黑樹;紅黑樹在查找、插入、刪除的復雜度都是o(logn)且性能穩定。
(2)c++內存的模型
操作系統將C語言代碼分為四個區:
1、棧區
2、堆區
3、全局區
4、程序代碼區
(3)malloc的原理
a 當開辟的空間小于 128K 時,調用 brk()函數,malloc 的底層實現是系統調用函數 brk(),其主要移動指針 _enddata(此時的 _enddata 指的是 Linux 地址空間中堆段的末尾地址,不是數據段的末尾地址)
b 當開辟的空間大于 128K 時,mmap()系統調用函數來在虛擬地址空間中(堆和棧中間,稱為“文件映射區域”的地方)找一塊空間來開辟。
(4)堆的概念
a 堆中某個節點的值總是不大于或不小于其父節點的值;
b 堆總是一棵完全二叉樹。
4 算法題
1 LRU 已經寫過答案
2 循環移動K個元素
3 堆排序
?
?
? ??
總結
- 上一篇: LRU缓存淘汰策略
- 下一篇: c语言经典程序100txt例,C语言经典