本篇博文主要介紹2021秋招時匯總的一些蝦皮后端面試過程中可能遇到的一些問題。
數據結構相關
1. 介紹一下哈希表
散列表(Hash table,也叫哈希表),是根據關鍵碼值(Key value)而直接進行訪問的數據結構。也就是說,它通過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數叫做散列函數,存放記錄的數組叫做散列表。
散列函數能使對一個數據序列的訪問過程更加迅速有效,通過散列函數,數據元素將被更快地定位。
常見的散列函數有:
- 直接尋址法
取關鍵字或關鍵字的某個線性函數值為散列地址
- 平方取中法
當無法確定關鍵字中哪幾位分布較均勻時,可以先求出關鍵字的平方值,然后按需要取平方值的中間幾位作為哈希地址
- 隨機數法
擇一隨機函數,取關鍵字的隨機值作為散列地址,通常用於關鍵字長度不等的場合
- 除留余數法
取關鍵字被某個不大於散列表表長m的數p除后所得的余數為散列地址。即 H(key) = key % p, p <= m
2. 怎么解決哈希沖突
- 開放尋址法 -- 當發生哈希沖突后,就去尋找下一個空的散列地址,只要散列表足夠大,這個空的位置一定能找到
線性探測: 此時這個位置已經存在數,那么就繼續對下一個位置進行探測,當到表尾時還沒有空位置,此時就返回表頭繼續找尋空位置
二次探測: Hi=(H(key) + di) MOD m, 每次查找的是距離上一個為 i^2 個距離的位置
- 再散列法
當散列表元素太多(即裝填因子 α 太大)時,查找效率會下降;當裝填因子過大時,解決的方法是加倍擴大散列表,這個過程叫做“再散列(Rehashing)”。Hash 表中每次發現 loadFactor==1 時,就開辟一個原來桶數組的兩倍空間(稱為新桶數組),然后把原來的桶數組中元素全部轉移過來到新的桶數組中。注意這里轉移是需要元素一個個重新哈希到新桶中的。實用最大裝填因子一般取 0.5 <= α<= 0.85
- 鏈地址法
當發生沖突時,該位置上的數據會用鏈表鏈起來,當表中的某些位置沒有結點時,該位置就為 NULL
- 公共溢出區
為所有沖突的關鍵字記錄建立一個公共的溢出區來存放。在查找時,對給定關鍵字通過散列函數計算出散列地址后,先與基本表的相應位置進行比對,如果相等,則查找成功;如果不相等,則到溢出表進行順序查找。如果相對於基本表而言,在有沖突的數據很少的情況下,公共溢出區的結構對查找性能來說還是非常高的。
3. 哈希表的擴容
假設以數組形式存放哈希表,當數組中元素過多時,可能會導致接下來存放數據時多次遇到沖突且尋找數據時也會遇到同樣的問題。這時哈希表引入了一個裝填因子(元素個數/數組長度),當裝填因子越大,表明數組可能存在的沖突越多,越需要擴容,實用的裝填因子大小為0.5-0.85。當裝填因子過大時,就需要考慮為哈希表進行擴容,一般來說,擴容選擇二倍的當前容量,一方面可以快速的進行位運算,另一方面能夠減少再哈希的沖突。需要注意的是,擴容的時候,原哈希表中的元素需要重新進行哈希。顯然,再哈希是個非常耗時的問題,引入了漸進式rehash。以下是哈希表漸進式 rehash 的詳細步驟:
- 為 ht[1] 分配空間, 讓字典同時持有 ht[0] 和 ht[1] 兩個哈希表。
*在字典中維持一個索引計數器變量 rehashidx , 並將它的值設置為 0 , 表示 rehash 工作正式開始。- 在 rehash 進行期間, 每次對字典執行添加、刪除、查找或者更新操作時, 程序除了執行指定的操作以外, 還會順帶將 ht[0] 哈希表在 rehashidx 索引上的所有鍵值對 rehash 到 ht[1] , 當 rehash 工作完成之后, 程序將 rehashidx 屬性的值增一。
- 隨着字典操作的不斷執行, 最終在某個時間點上, ht[0] 的所有鍵值對都會被 rehash 至 ht[1] , 這時程序將 rehashidx 屬性的值設為 -1 , 表示 rehash 操作已完成。
4. 數組和鏈表的區別
- 數組必須事先定義固定的長度(元素個數),不能適應數據動態地增減的情況,即數組的大小一旦定義就不能改變。當數據增加時,可能超出原先定義的元素個數;當數據減少時,造成內存浪費;鏈表動態地進行存儲分配,可以適應數據動態地增減的情況,且可以方便地插入、刪除數據項。(數組中插入、刪 除數據項時,需要移動其它數據項)。
- (靜態)數組從棧中分配空間(用 new 創建的在堆中), 對於程序員方便快速,但是自由度小;鏈表從堆中分配空間, 自由度大但是申請管理比較麻煩。
- 數組在內存中是連續存儲的,因此,可以利用下標索引進行隨機訪問;鏈表是鏈式存儲結構,在訪問元素的時候只能通過線性的方式由前到后順序訪問,所以訪問效率比數組要低。
5. 二叉樹、二叉搜索樹、平衡二叉樹、紅黑樹
- 二叉樹特點是每個結點最多只能有兩棵子樹,且有左右之分。
- 二叉查找樹(Binary Search Tree),(又:二叉搜索樹,二叉排序樹)它或者是一棵空樹,或者是具有下列性質的二叉樹: 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; 若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;它的左、右子樹也分別為二叉排序樹。
- 平衡二叉樹(AVL)。它是一棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,並且左右兩個子樹都是一棵平衡二叉樹。這個方案很好的解決了二叉查找樹退化成鏈表的問題,把插入,查找,刪除的時間復雜度最好情況和最壞情況都維持在O(logN)。但是頻繁旋轉會使插入和刪除犧牲掉O(logN)左右的時間,不過相對二叉查找樹來說,時間上穩定了很多
- 紅黑樹。一種二叉查找樹,但在每個節點增加一個存儲位表示節點的顏色,可以是紅或黑(非紅即黑)。通過對任何一條從根到葉子的路徑上各個節點着色的方式的限制,紅黑樹確保沒有一條路徑會比其它路徑長出兩倍,因此,紅黑樹是一種弱平衡二叉樹(由於是弱平衡,可以看到,在相同的節點情況下,AVL樹的高度低於紅黑樹),相對於要求嚴格的AVL樹來說,它的旋轉次數少,所以對於搜索,插入,刪除操作較多的情況下,我們就用紅黑樹。
性質:1. 每個節點非紅即黑 2. 根節點是黑的; 3. 每個葉節點(葉節點即樹尾端NULL指針或NULL節點)都是黑的; 4. 如果一個節點是紅的,那么它的兩兒子都是黑的; 5. 對於任意節點而言,其到葉子點樹NULL指針的每條路徑都包含相同數目的黑節點; 6. 每條路徑都包含相同的黑節點。- 平衡二叉樹和紅黑樹對比。
結構對比: AVL 的結構高度平衡,RBT 的結構基本平衡。平衡度 AVL > RBT。
查找對比: AVL 查找時間復雜度最好,最壞情況都是 O(logN)。RBT 查找時間復雜度最好為 O(logN),最壞情況下比 AVL 略差。
插入刪除對比: 1. AVL 的插入和刪除結點很容易造成樹結構的不平衡,而 RBT 的平衡度要求較低。因此在大量數據插入的情況下,RBT 需要通過旋轉變色操作來重新達到平
衡的頻度要小於 AVL。2. 如果需要平衡處理時,RBT 比 AVL 多一種變色操作,而且變色的時間復雜度在 O(logN)數量級上。但是由於操作簡單,所以在實踐中這種變色仍然是非常快速的。3. 當插入一個結點引起了樹的不平衡,AVL 和 RBT 都最多需要 2 次旋轉操作。但刪除一個結點引起不平衡后,AVL 最多需要 logN 次旋轉操作,而 RBT 最多只需要 3 次。因此兩者插入一個結點的代價差不多,但刪除一個結點的代價 RBT要低一些。4. AVL 和 RBT 的插入刪除代價主要還是消耗在查找待操作的結點上。因此時間復雜度基本上都是與 O(logN) 成正比的。
總體評價:大量數據實踐證明,RBT 的總體統計性能要好於平衡二叉樹。
紅黑樹詳解
6. B樹、B+樹
B 樹:
- 一種二叉搜索樹。
- 除根節點外的所有非葉節點至少含有(M/2(向上取整)-1)個關鍵字,每個節點最多有M-1個關鍵字,並且以升序排列。所以M階B樹的除根節點外的所有非葉節點的關鍵字取值區間為[M/2-1(向上取整),M-1]。
- 每個葉節點最多有M-1個關鍵字。
B+樹:
- 有n棵子樹的非葉子結點中含有n個關鍵字(b樹是n-1個),這些關鍵字不保存數據,只用來索引,所有數據都保存在葉子節點(b樹是每個關鍵字都保存數據)。
- 所有的葉子結點中包含了全部關鍵字的信息,及指向含這些關鍵字記錄的指針,且葉子結點本身依關鍵字的大小自小而大順序鏈接(葉子節點組成一個鏈表)。
- 所有的非葉子結點可以看成是索引部分,結點中僅含其子樹中的最大(或最小)關鍵字。
- 通常在b+樹上有兩個頭指針,一個指向根結點,一個指向關鍵字最小的葉子結點。
- 同一個數字會在不同節點中重復出現,根節點的最大元素就是b+樹的最大元素。
B樹與B+樹的區別:
- B樹每個節點都存儲數據,所有節點組成這棵樹。B+樹只有葉子節點存儲數據(B+數中有兩個頭指針:一個指向根節點,另一個指向關鍵字最小的葉節點),葉子節點包含了這棵樹的所有數據,所有的葉子結點使用鏈表相連,便於區間查找和遍歷,所有非葉節點起到索引作用。
- B樹中葉節點包含的關鍵字和其他節點包含的關鍵字是不重復的,B+樹的索引項只包含對應子樹的最大關鍵字和指向該子樹的指針,不含有該關鍵字對應記錄的存儲地址。
- B樹中每個節點(非根節點)關鍵字個數的范圍為m/2(向上取整)-1,m-1,並且具有n個關鍵字的節點包含(n+1)棵子樹。B+樹中每個節點(非根節點)關鍵字個數的范圍為m/2(向上取整),m,具有n個關鍵字的節點包含(n)棵子樹。
- B+樹中查找,無論查找是否成功,每次都是一條從根節點到葉節點的路徑。
B樹的優點:
- B樹的每一個節點都包含key和value,因此經常訪問的元素可能離根節點更近,因此訪問也更迅速。
B+樹的優點:
- 所有的葉子結點使用鏈表相連,便於區間查找和遍歷。B樹則需要進行每一層的遞歸遍歷。相鄰的元素可能在內存中不相鄰,所以緩存命中性沒有B+樹好。
- b+樹的中間節點不保存數據,能容納更多節點元素。
B樹與B+樹的共同優點:
- 考慮磁盤IO的影響,它相對於內存來說是很慢的。數據庫索引是存儲在磁盤上的,當數據量大時,就不能把整個索引全部加載到內存了,只能逐一加載每一個磁盤頁(對應索引樹的節點)。所以我們要減少IO次數,對於樹來說,IO次數就是樹的高度,而“矮胖”就是b樹的特征之一,m的大小取決於磁盤頁的大小。
數據庫相關
1. ACID
原子性:指事務是一個不可再分割的工作單位,事務中的操作要么都發生,要么都不發生。事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣
一致性:指事務使得系統從一個一致的狀態轉換到另一個一致狀態。這是說數據庫事務不能破壞關系數據的完整性以及業務邏輯上的一致性
隔離性:多個事務並發訪問時,事務之間是隔離的,一個事務不應該影響其它事務運行效果。這指的是在並發環境中,當不同的事務同時操縱相同的數據時,每個事務都有各自的完整數據空間。由並發事務所做的修改必須與任何其他並發事務所做的修改隔離。
持久性:意味着在事務完成以后,該事務所對數據庫所作的更改便持久的保存在數據庫之中,並不會被回滾。即使出現了任何事故比如斷電等,事務一旦提交,則持久化保存在數據庫中。
2. 四種隔離級別以及 MySQL 的默認隔離級別
READ UNCIMMITTED(讀未提交) 事務中的修改,即使沒有提交,其他事務也可以看得到。會出現臟讀現象
READ COMMITTED(讀提交)大多數數據庫系統的默認隔離級別是 READ COMMITTED(mySQL 不是),這種隔離級別就是一個事務的開始,只能看到已經完成的事務的結果,正在執行的,是無法被其他事務看到的。這種級別會出現讀取舊數據的現象
REPEATABLE READ(可重復讀)REPEATABLE READ 解決了臟讀的問題,該級別保證了每行的記錄的結果是一致的,也就是上面說的讀了舊數據的問題,但是卻無法解決另一個問題,幻行
SERIALIZABLE(可串行化)SERIALIZABLE 是最高的隔離級別,它通過強制事務串行執行(注意是串行),避免了前面的幻讀情況,由於他大量加上鎖,導致大量的請求超時,因此性能會比較底下,再特別需要數據一致性且並發量不需要那么大的時候才可能考慮這個隔離級別。
MYSQL的默認隔離級別是可重復讀級別。
3. MYSQL怎么實現多版本(MVCC)的
MVCC就是為了實現讀-寫沖突不加鎖,而這個讀指的就是快照讀, 而非當前讀,當前讀實際上是一種加鎖的操作,是悲觀鎖的實現。
在Mysql中進行數據操作時會將操作的相反命令寫入undo log,根據各種策略讀取時非阻塞就是MVCC,undo log中的行就是MVCC中的多版本。一般認為MVCC有下面幾個特點
- 每行數據都存在一個版本,每次數據更新時都更新該版本
- 修改時Copy出當前版本隨意修改,個事務之間無干擾
- 保存時比較版本號,如果成功(commit),則覆蓋原記錄;失敗則放棄copy(rollback)
Innodb的實現方式是:
- 事務以排他鎖的形式修改原始數據
- 把修改前的數據存放於undo log,通過回滾指針與主數據關聯
- 修改成功(commit)啥都不做,失敗則恢復undo log中的數據(rollback)
4. 復合索引
索引有兩個特征,即唯一性索引和復合索引。唯一性索引保證在索引列中的全部數據是唯一的,不會包含冗余數據。復合索引就是一個索引創建在兩個列或者多個列上,搜索時需要兩個或者多個索引列作為一個關鍵值。
創建索引
key index_name (attr1, attr2, ...); # 聯合索引 key index_name (attr); # 唯一索引
5. 聚簇索引和非聚簇索引
聚簇索引的數據的物理存放順序與索引順序是一致的,即:只要索引是相鄰的,那么對應的數據一定也是相鄰地存放在磁盤上的。
在聚簇索引下,數據在物理上按順序排在數據頁上,重復值也排在一起,因而在那些包含范圍檢查(between、<、<=、>、>=)或使用group by或orderby的查詢時,一旦找到具有范圍中第一個鍵值的行,具有后續索引值的行保證物理上毗連在一起而不必進一步搜索,避免了大范圍掃描,可以大大提高查詢速度。
非聚簇索引,葉級頁指向表中的記錄,記錄的物理順序與邏輯順序沒有必然的聯系。
每個表可以有250個索引,其中至多有一個聚簇索引。
非聚簇索引需要大量的硬盤空間和內存。另外,雖然非聚簇索引可以提高從表中取數據的速度,它也會降低向表中插入和更新數據的速度。每當你改變了一個建立了非聚簇索引的表中的數據時,必須同時更新索引。
6. MyISAM和InnoDB差別
- Innodb 引擎提供了對數據庫 ACID 事務的支持,並且實現了 SQL 標准的四種隔離級別。該引擎還提供了行級鎖和外鍵約束,它的設計目標是處理大容量數據庫系統,它本身其實就是基於 MySQL 后台的完整數據庫系統,MySQL運行時 Innodb 會在內存中建立緩沖池,用於緩沖數據和索引。但是該引擎不支持 FULLTEXT類型的索引,而且它沒有保存表的行數,當 SELECT COUNT(*) FROM TABLE 時需要掃描全表。當需要使用數據庫事務時,該引擎當然是首選。由於鎖的粒度更小,寫操作不會鎖定全表,所以在並發較高時,使用 Innodb 引擎會提升效率。但是使用行級鎖也不是絕對的,如果在執行一個 SQL 語句時 MySQL 不能確定要掃描的范圍,InnoDB 表同樣會鎖全表。
- MyIASM 是 MySQL 默認的引擎,但是它沒有提供對數據庫事務的支持,也不支持行級鎖和外鍵,因此當 INSERT(插入)或 UPDATE(更新)數據時即寫操作需要鎖定整個表,效率便會低一些。不過和 Innodb 不同,MyIASM 中存儲了表的行數,於是 SELECT COUNT(*) FROM TABLE 時只需要直接讀取已經保存好的值而不需要進行全表掃描。如果表的讀操作遠遠多於寫操作且不需要數據庫事務的支持,那么 MyIASM 也是很好的選擇。
- 大尺寸的數據集趨向於選擇 InnoDB 引擎,因為它支持事務處理和故障恢復。數據庫的大小決定了故障恢復的時間長短,InnoDB 可以利用事務日志進行數據恢復,這會比較快。主鍵查詢在 InnoDB 引擎下也會相當快,不過需要注意的是如果主鍵太長也會導致性能問題。大批的 INSERT 語句(在每個 INSERT 語句中寫入多行,批量插入)在 MyISAM 下會快一些,但是 UPDATE 語句在 InnoDB 下則會更快一些,尤其是在並發量大的時候。
7. Mysql 的 redo和undo
Undo日志記錄某數據被修改前的值,可以用來在事務失敗時進行回滾;Redo日志記錄某數據塊被修改后的值,可以用來恢復未寫入data file的已成功事務更新的數據。
redo log是重做日志,提供前滾操作,undo log是回滾日志,提供回滾操作
undo log不是redo log的逆向過程,其實它們都算是用來恢復的日志:
redo log通常是物理日志,記錄的是數據頁的物理修改,而不是某一行或某幾行修改成怎樣怎樣,它用來恢復提交后的物理數據頁(恢復數據頁,且只能恢復到最后一次提交的位置)。undo用來回滾行記錄到某個版本。undo log一般是邏輯日志,根據每行記錄進行記錄。
數據庫進行任何寫入操作的時候都是要先寫日志的,同樣的道理,我們在執行事務的時候數據庫首先會記錄下這個事務的 redo 操作日志,然后才開始真正操作數據庫,在操作之前首先會把日志文件寫入磁盤,那么當突然斷電的時候,即使操作沒有完成,在重新啟動數據庫時候,數據庫會根據當前數據的情況進行 undo 回滾或者是 redo 前滾,這樣就保證了數據的強一致性。
8. MySQL主從同步有哪些策略?insert到master是等同步完成再響應還是?
MySQL主從復制的基礎是主服務器對數據庫修改記錄二進制日志,從服務器通過主服務器的二進制日志自動執行更新。一句話表示就是,主數據庫做什么,從數據庫就跟着做什么。
mysql復制的類型:
- 基於語句的復制 :主庫把sql語句寫入到bin log中,完成復制
- 基於行數據的復制:主庫把每一行數據變化的信息作為事件,寫入到bin log,完成復制
- 混合復制:上面兩個結合體,默認用語句復制,出問題時候自動切換成行數據復制
- 和上面相對應的日志格式也有三種:STATEMENT,ROW,MIXED
- STATEMENT模式(SBR): 每一條會修改數據的sql語句會記錄到binlog中。優點是並不需要記錄每一條sql語句和每一行的數據變化,減少了binlog日志量,節約IO,提高性能。缺點是在某些情況下會導致master-slave中的數據不一致(如sleep()函數,last_insert_id(),以及user-defined functions(udf)等會出現問題)
- ROW模式(RBR): 不記錄每條sql語句的上下文信息,僅需記錄哪條數據被修改了,修改成什么樣了。而且不會出現某些特定情況下的存儲過程、或function、或trigger的調用和觸發無法被正確復制的問題。缺點是會產生大量的日志,尤其是alter table的時候會讓日志暴漲。
- MIXED模式(MBR)以上兩種模式的混合使用,一般的復制使用STATEMENT模式保存binlog,對於STATEMENT模式無法復制的操作使用ROW模式保存binlog,MySQL會根據執行的SQL語句選擇日志保存方式。
主從復制工作原理剖析:
- Master 數據庫只要發生變化,立馬記錄到Binary log 日志文件中
- Slave數據庫啟動一個I/O thread連接Master數據庫,請求Master變化的二進制日志
- Slave I/O獲取到的二進制日志,保存到自己的Relay log 日志文件中
- Slave 有一個 SQL thread定時檢查Realy log是否變化,有變化那么就更新數據
解決的問題有:
- 實現服務器負載均衡: 可以通過在主服務器和從服務器之間切分處理客戶查詢的負荷,從而得到更好的客戶響應時間
- 通過復制實現數據的異地備份
- 提高數據庫系統的可用性: 當主服務器出現問題時,數據庫管理員可以馬上讓從服務器作為主服務器,用來數據的更新與查詢服務
9. 慢查詢優化
- 優化數據庫結構
- 分解關聯查詢: 很多高性能的應用都會對關聯查詢進行分解,就是可以對每一個表進行一次單表查詢,然后將查詢結果在應用程序中進行關聯,很多場景下這樣會更高效。
- 增加索引
- 建立視圖
- 優化查詢語句
- 添加存儲過程
- 冗余保存數據
10. 主鍵索引和唯一索引的區別
- 在數據庫關系圖中為表定義主鍵將自動創建主鍵索引,主鍵索引是唯一索引的特定類型。該索引要求主鍵中的每個值都唯一。當在查詢中使用主鍵索引時,它還允許對數據的快速訪
問。 - 主鍵索引不僅僅具有索引的特征,還包含着主鍵約束,如不為空,值唯一的特征
- 主鍵可以被其他表引用為外鍵,而唯一索引不能
- 一個表最多只能創建一個主鍵,但可以創建多個唯一索引
11. Innodb 自增主鍵
InnoDB使用聚集索引,數據記錄本身被存於主索引(一顆B+Tree)的葉子節點上。這就要求同一個葉子節點內(大小為一個內存頁或磁盤頁)的各條數據記錄按主鍵順序存放,因此每當有一條新的記錄插入時,MySQL會根據其主鍵將其插入適當的節點和位置,如果頁面達到裝載因子(InnoDB默認為15/16),則開辟一個新的頁(節點)。如果表使用自增主鍵,那么每次插入新的記錄,記錄就會順序添加到當前索引節點的后續位置,當一頁寫滿,就會自動開辟一個新的頁。這樣就會形成一個緊湊的索引結構,近似順序填滿。由於每次插入時也不需要移動已有數據,因此效率很高,也不會增加很多開銷在維護索引上。
12. 忘了寫主鍵索引,但是已經有幾萬條數據,該怎么優化
將數據導出,添加索引,導入數據
13. innodb和myism對count的支持?為什么innodb不像myism存儲記錄總條數
因為MyISAM會保存表的具體行數,MyISAM只要簡單地讀出保存好的行數即可。然而,InnoDB存儲引擎不會保存表的具體行數,因此,在InnoDB存儲引擎中,InnoDB要掃描一遍整個表來計算有多少行。
InnoDB的事務特性,在同一時刻表中的行數對於不同的事務而言是不一樣的,因此count統計會計算對於當前事務而言可以統計到的行數,而不是將總行數儲存起來方便快速查詢。
14. mysql的存儲引擎有哪些?索引數據結構有哪些?
- InnoDB存儲引擎
- MyISAM存儲引擎
- MEMORY存儲引擎
MEMORY存儲引擎將表中的數據存儲到內存中,為查詢和引用其他表數據提供快速訪問。
- Archive存儲引擎
如果只有INSERT和SELECT操作,可以選擇Archive,Archive支持高並發的插入操作,但是本身不是事務安全的。Archive非常適合存儲歸檔數據,如記錄日志信息可以使用Archive
計算機網絡
1. 介紹一下 OSI
OSI七層網絡模型
- 物理層:規定通信設備的機械的、電氣的、功能的和過程的特性,用以建立、維護和拆除物理鏈路連接。在這一層,數據的單位稱為比特(bit)。屬於物理層定義的典型規范代表包括:EIA/TIA RS-232、EIA/TIA RS-449、V.35、RJ-45 等
- 數據鏈路層:在物理層提供比特流服務的基礎上,建立相鄰結點之間的數據鏈路,通過差
錯控制提供數據幀(Frame)在信道上無差錯的傳輸,並進行各電路上的動作系列。數據鏈路層在不可靠的物理介質上提供可靠的傳輸。該層的作用包括:物理地址尋址、數據的成幀、流量控制、數據的檢錯、重發等。在這一層,數據的單位稱為幀(frame)。數據鏈路層協議的代表包括:SDLC、HDLC、PPP、STP、幀中繼等。 - 網絡層:在 計算機網絡中進行通信的兩個計算機之間可能會經過很多個數據鏈路,也可能還要經過很多通信子網。網絡層的任務就是選擇合適的網間路由和交換結點,確保數據及時傳送。網絡層將數據鏈路層提供的幀組成數據包,包中封裝有網絡層包頭,其中含有邏輯地址信息- -源站點和目的站點地址的網絡地址。IP 是第 3 層問題的一部分,此外還有一些路由協議和地址解析協議(ARP)。有關路由的一切事情都在這第 3 層處理。地址解析和路由是 3 層的重要目的。網絡層還可以實現擁塞控制、網際互連等功能。在這一層,數據的單位稱為數據包(packet)。網絡層協議的代表包括:IP、IPX、RIP、OSPF 等。
- 傳輸層:第 4 層的數據單元也稱作數據包(packets)。但是,當你談論 TCP 等具體的協議時又有特殊的叫法,TCP 的數據單元稱為段 (segments)而 UDP 協議的數據單元稱為“數據報(datagrams)”。這個層負責獲取全部信息,因此,它必須跟蹤數據單元碎片、亂序到達的數據包和其它在傳輸過程中可能發生的危險。第 4 層為上層提供端到端(最終用戶到最終用戶)的透明的、可靠的數據傳輸服務。所謂透明的傳輸是指在通信過程中 傳輸層對上層屏蔽了通信傳輸系統的具體細節。傳輸層協議的代表包括:TCP、UDP、SPX 等。
- 會話層:在會話層及以上的高層次中,數據傳送的單位不再另外命名,而是統稱為報文。會話層不參與具體的傳輸,它提供包括訪問驗證和會話管理在內的建立和維護應用之間通信的機制。如服務器驗證用戶登錄便是由會話層完成的。
- 表示層:這一層主要解決擁護信息的語法表示問題。它將欲交換的數據從適合於某一用戶的抽象語法,轉換為適合於 OSI 系統內部使用的傳送語法。即提供格式化的表示和轉換數據服務。數據的壓縮和解壓縮, 加密和解密等工作都由表示層負責。
- 應用層:為操作系統或網絡應用程序提供訪問網絡服務的接口。應用層協議的代表包括:Telnet、FTP、HTTP、SNMP 等
2. 輸入網址到頁面渲染的過程
- 瀏覽器構建HTTP Request請求
- 網絡傳輸
- 服務器構建HTTP Response 響應
- 網絡傳輸
- 瀏覽器渲染頁面
DNS解析URL地址、生成HTTP請求報文、構建TCP連接、使用IP協議選擇傳輸路線、數據鏈路層保證數據的可靠傳輸、物理層將數據轉換成電子、光學或微波信號進行傳輸
3. 介紹一下不對稱加密以及對稱加密
- 對稱加密是最快速、最簡單的一種加密方式,加密(encryption)與解密(decryption)用的是同樣的密鑰(secret key)。對稱加密的一大缺點是密鑰的管理與分配,換句話說,如何把密鑰發送到需要解密你的消息的人的手里是一個問題。在發送密鑰的過程中,密鑰有很大的風險會被黑客們攔截。現實中通常的做法是將對稱加密的密鑰進行非對稱加密,然后傳送給需要它的人。
- 非對稱加密為數據的加密與解密提供了一個非常安全的方法,它使用了一對密鑰,公鑰(public key)和私鑰(private key)。私鑰只能由一方安全保管,不能外泄,而公鑰則可以發給任何請求它的人。非對稱加密使用這對密鑰中的一個進行加密,而解密則需要另一個密鑰。
4. HTTP 1.0、HTTP 2.0到HTTP 3.0以及HTTPS
- HTTP1.0 使用的是非持久連接,主要缺點是客戶端必須為每一個待請求的對象建立並維護一個新的連接,即每請求一個文檔就要有兩倍RTT 的開銷。因為同一個頁面可能存在多個對象,所以非持久連接可能使一個頁面的下載變得十分緩慢,而且這種 短連接增加了網絡傳輸的負擔。(RTT(Round Trip Time):一個連接的往返時間)
- HTTP1.1 支持長連接, 在HTTP1.0的基礎上引入了更多的緩存控制策略,引入了請求范圍設置,優化了帶寬,在錯誤通知管理中新增了錯誤狀態響應碼,增加了Host頭處理,可以傳遞主機名(hostname),但是傳輸內容是明文,不夠安全
- HTTP 1.x優化(SPDY):SPDY 並不是新的一種協議,而是在 HTTP 之前做了一層會話層。為了達到減少頁面加載時間的目標,SPDY 引入了一個新的二進制分幀數據層,以實現優先次序、最小化及消除不必要的網絡延遲,目的是更有效地利用底層 TCP 連接。為多路復用設立了請求優先級,對header部分進行了壓縮,引入了HTTPS加密傳輸,客戶端可以在緩存中取到之前請求的內容。
- HTTP2.0:支持明文傳輸,而HTTP 1.X強制使用SSL/TLS加密傳輸,和HTTP 1.x使用的header壓縮方法不同。HTTP2.0 基於二進制格式進行解析,而HTTP 1.x基於文本格式進行解析,多路復用,HTTP1.1是多個請求串行化單線程處理,HTTP 2.0是並行執行,一個請求超時並不會影響其他請求。多路復用可以繞過瀏覽器限制同一個域名下的請求數量的問題,進而提高了網頁的性能。
- HTTP 3.0 (QUIC):QUIC (Quick UDP Internet Connections), 快速 UDP 互聯網連接
,QUIC是基於UDP協議的。
- 線頭阻塞(HOL)問題的解決更為徹底:基於TCP的HTTP/2,盡管從邏輯上來說,不同的流之間相互獨立,不會相互影響,但在實際傳輸方面,數據還是要一幀一幀的發送和接收,一旦某一個流的數據有丟包,則同樣會阻塞在它之后傳輸的流數據傳輸。而基於UDP的QUIC協議則可以更為徹底地解決這樣的問題,讓不同的流之間真正的實現相互獨立傳輸,互不干擾。
- 切換網絡時的連接保持: 當前移動端的應用環境,用戶的網絡可能會經常切換,比如從辦公室或家里出門,WiFi斷開,網絡切換為3G或4G。基於TCP的協議,由於切換網絡之后,IP會改變,因而之前的連接不可能繼續保持。而基於UDP的QUIC協議,則可以內建與TCP中不同的連接標識方法,從而在網絡完成切換之后,恢復之前與服務器的連接
HTTPS: HTTPS運行在安全套接字協議(Secure Sockets Layer,SSL )或傳輸層安全協議(Transport Layer Security,TLS)之上,所有在TCP中傳輸的內容都需要經過加密。HTTP的端口是80,HTTPS的端口是443
5. TCP 的擁塞控制、流量控制、滑動窗口
- TCP擁塞控制用於控制發送端向網絡一次連續寫入的數據量。
- 使用的方法有 當發送窗口大小小於發送門限時,使用慢開始指數增大窗口,當發送窗口大於發送門限時,使用擁塞避免算法加性增加發送窗口大小,當出現網絡擁塞時,門限減為當前發送窗口的一半,重新開始慢啟動。另一種快速重傳的方法是:如果收到連續三個ACK,則視作網絡的阻塞程度不嚴重,將門限減為當前發送窗口大小的一半,將發送窗口尺寸設置為當前門限大小,啟動擁塞避免算法。
- 如果發送方把數據發送得過快,接收方可能會來不及接收,這就會造成數據的丟失。TCP 的流量控制是利用滑動窗口機制實現的,接收方在返回的 ACK 中會包含自己的接收窗口(RWND)的大小,TCP 頭部有個 16 位窗口大小,表示的就是 RWND。以控制發送方的數據發送。
6. TCP與UDP
- TCP 面向連接的,UDP 是無連接的
- TCP 面向字節流,UDP 面向數據包 (字節流:發送端執行的寫操作數和接收端執行的讀操作數之間沒有任何數量關系)
- Tcp 通過校驗和,重傳控制,序號標識,滑動窗口、確認應答實現可靠傳輸
- UDP 具有較好的實時性,工作效率比 TCP 高,適用於對高速傳輸和實時性有較高的通信或廣播通信
- 每一條 TCP 連接只能是點到點的, UDP 支持一對一,一對多,多對一和多對多的交互通信
- TCP 對系統資源要求較多,UDP 對系統資源要求較少
- 若通信數據完整性需讓位與通信實時性,則應該選用 TCP 協議(如文件傳輸、重要狀態的更新等);反之,則使用 UDP 協議(如視頻傳輸、實時通信等)
7. 為什么三次握手、SYN攻擊、SYN攻擊的應對方法
采用兩次握手,那么若 Client 向 Server 發起的包 A1 如果在傳輸鏈路上遇到的故障,導致傳輸到 Server 的時間相當滯后,在這個時間段由於 Client 沒有收到 Server的對於包 A1 的確認,那么就會重傳一個包 A2,假設服務器正常收到了 A2 的包,然后返回確認 B2 包。由於沒有第三次握手,這個時候 Client 和 Server 已經建立連接了。再假設 A1 包隨后在鏈路中傳到了 Server,這個時候 Server 又會返回 B1 包確認,但是由於 Client 已經清除了 A1 包,所以 Client 會丟棄掉這個確認包,但是 Server 會保持這個相當於“僵屍”的連接。
TCP 在傳遞數據前需要經過三次握手,SYN 攻擊的原理就是向服務器發送SYN 數據包,並偽造源 IP 地址,服務器在收到 SYN 數據包時,會將連接加入 backlog 隊列,並向源 IP 發送 SYN-ACK 數據包,並等待 ACK 數據包,以完成三次握手建立連接。由於源 IP 地址是偽造的不存在主機 IP,所以服務器無法收到 ACK 數據包,並會不斷重發,同時 backlog 隊列被不斷被攻擊的 SYN 連接占滿,導致無法處理正常的連接。
針對 SYN 攻擊的幾個環節,提出相應的處理方法:
- 減少 SYN-ACK 數據包的重發次數
- 增加 backlog 隊列
- 限制 SYN 並發數
- 使用 SYN Cookie 技術
8. TCP四次揮手的TIME_WAIT
首先調用 close()發起主動關閉的一方,在發送最后一個 ACK 之后會進入 time_wait 的狀態,也就說該發送方會保持 2MSL 時間之后才會回到初始狀態。MSL 指的是數據包在網絡中的最大生存時間,一般是2min。
為什么存在 time_wait:
- 可靠地終止 TCP 連接。維持一個狀態防止對端沒有接受到最后一個 ACK 報文段
- 保證讓遲來的 TCP 報文段有足夠的時間被識別從而丟棄。TCP 報文段最大生存時間是 MSL,2MSL 保證兩個傳輸方向上沒有接收到的、遲到的 TCP 報文段全部消失。一個使用原本 IP 和端口的新連接可以在 2MSL 之后安全建立,而絕對不會接收到原有連接上的數據。
9. TCP 如何保證數據傳輸的可靠性
- 可靠連接
- 序號
- 應答機制 序列號與ACK
- 超時重傳
- 流量控制
- 擁塞控制
- CRC校驗
- TCP 對接收到的 TCP 報文段重排、整理,再交付給應用層
10. HTTP狀態碼
- 1XX 信息碼,服務器收到請求,需要請求者繼續執行操作;100 正常,客戶端應該繼續請求
- 2XX 成功碼,操作被成功接收並處理;200 正常處理,204 成功處理,但是沒有內容返回
- 3XX 重定向,需要進一步的操作以完成請求;301 永久重定向,302 臨時重定向
- 4XX 客戶端錯誤,請求包含語法錯誤或無法完成請求;400 語法錯誤,401 要求身份認證,403 禁止 404 找不到資源
- 5XX 服務器錯誤,服務器在處理請求的過程中發生了錯誤 500 內部服務器錯誤,503服務不可用
11. 路由器的作用
12. 我們的電腦能轉發網絡嗎,原理是什么
14. 五層網絡IO模型
- 物理層
- 數據鏈路層
- 網絡層
- 運輸層
- 應用層 (OSI會話層、表示層、應用層)
15. HTTP協議怎么解決拆包粘包的問題
TCP發送端為了將多個發往接收端的包,更有效的發到對方,使用了優化方法(Nagle 算
法),將多次間隔較小、數據量小的數據,合並成一個大的數據塊,然后進行封包。這樣,接收端,就難於分辨出來了,必須提供科學的拆包機制。
TCP 粘包是指發送方發送的若干包數據到接收方接收時粘成一包,從接收緩沖區看,后一包數據的頭緊接着前一包數據的尾。
出現粘包的原因,發送端使用Nagle算法將多個小TCP合並發送,接收端將多個TCP包緩存接收。
解決方案:
- 發送方:關閉Nagle算法
- 接收方:在應用層處理
16. HTTPS握手的過程,用到的加密算法
- 瀏覽器請求連接
- 服務器返回證書:證書里面包含了網站地址,加密公鑰,以及證書的頒發機構等信息
- 瀏覽器收到證書后作以下工作
- 驗證證書的合法性
- 生成隨機(對稱)密碼,取出證書中提供的公鑰對隨機密碼加密
- 將之前生成的加密隨機密碼等信息發送給網站
- 服務器收到消息后作以下的操作
- 使用自己的私鑰解密瀏覽器用公鑰加密后的消息,並驗證 HASH 是否與瀏覽器發來的一致;獲得瀏覽器發過來的對稱秘鑰
- 使用加密的隨機對稱密碼加密一段消息,發送給瀏覽器
- 瀏覽器解密並計算握手消息的 HASH:如果與服務端發來的 HASH 一致,此時握手過程結束,之后進行通信
冪等性怎么確保的
- 通過唯一的業務單號來保證
TCP報文內容,http報文內容
ARP協議的作用
ARP(地址解析)協議是一種解析協議,本來主機是完全不知道這個 IP 對應的是哪個主機的哪個接口,當主機要發送一個 IP 包的時候,會首先查一下自己的 ARP 高速緩存表(最近數據傳遞更新的 IP-MAC 地址對應表),如果查詢的 IP-MAC 值對不存在,那么主機就向網絡廣播一個 ARP請求包,這個包里面就有待查詢的 IP 地址,而直接收到這份廣播的包的所有主機都會查詢自己的 IP 地址,如果收到廣播包的某一個主機發現自己符合條件,那么就回應一個 ARP 應答包(將自己對應的 IP-MAC 對應地址發回主機),源主機拿到 ARP 應答包后會更新自己的 ARP 緩存表。源主機根據新的 ARP 緩存表准備好數據鏈路層的的數據包發送工作。
HTTP 無狀態 無連接
- 無連接的含義是限制每次連接只處理一個請求。服務器處理完客戶的請求,並收到客戶的應答后,即斷開連接。采用這種方式可以節省傳輸時間。為請求時建連接、請求完釋放連接,以盡快將資源釋放出來服務其他客戶端,可以加KeepAlive彌補無連接的問題
- 無狀態是指協議對於事務處理沒有記憶能力,服務器不知道客戶端是什么狀態。即我們給服務器發送 HTTP 請求之后,服務器根據請求,會給我們發送數據過來,但是,發送完,不會記錄任何信息。 可以通過Cookie和Session來彌補這個問題。
Cookie 和 Session
- cookie 是一種發送到客戶瀏覽器的文本串句柄,並保存在客戶機硬盤上,可以用來在某個WEB站點會話間持久的保持數據。
- Session的本質上也是cookie,但是不同點是存在服務器上的。這就導致,你如果使用cookie,你關閉瀏覽器之后,就丟掉Cookie了,但是如果關掉瀏覽器,重新打開之后,發現還有相應的信息,那就說明用的是Session。因為cookie是存在本地的,所以也會有相應的安全問題,攻擊者可以去偽造他,填寫相應的字段名,就能登錄你的賬戶,還有如果cookie的有效期很長的話,也不安全。
- session 由服務器產生,對於客戶端,只存儲session id在cookie中
操作系統
進程與線程的區別

協程與線程
- 協程是一種比線程更加輕量級的存在。一個線程可以擁有多個協程;協程不是被操作系統內核管理,而完全是由程序所控制
- 協程的開銷遠遠小於線程
- 協程擁有自己寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其他地方,在切換回來的時候,恢復先前保存的寄存器上下文和棧
- 每個協程表示一個執行單元,有自己的本地數據,與其他協程共享全局數據和其他資源
- 跨平台、跨體系架構、無需線程上下文切換的開銷、方便切換控制流,簡化編程模型
- 協程又稱為微線程,協程的完成主要靠 yeild 關鍵字,協程執行過程中,在子程序內部可中斷,然后轉而執行別的子程序,在適當的時候再返回來接着執行
- 協程極高的執行效率,和多線程相比,線程數量越多,協程的性能優勢就越明顯
- 不需要多線程的鎖機制
同一個進程中,不同線程什么是共享的,什么不是共享的(操作棧、程序計數器)
共享:
- 進程代碼段
- 進程的公有數據(利用這些共享的數據,線程很容易的實現相互之間的通訊)
- 進程打開的文件描述符
- 信號的處理器
- 進程的當前目錄
- 進程用戶ID與進程組ID
私有:
- 線程ID
- 寄存器組的值 (PC指針)
- 線程的堆棧
- 錯誤返回碼
- 線程的信號屏蔽碼
線程上下文切換的時候,什么東西需要保存、什么東西需要恢復
進程切換步驟:
- 保存當前進程的上下文
- 恢復某個先前被搶占的進程的上下文
- 將控制傳遞給這個新恢復的進程
詳細步驟:
- 保存處理器上下文環境即 PSW、PC 等寄存器和堆棧內容,保存到內核堆棧中
- 調整被中斷進程的 PCB 進程控制塊信息,改變進程狀態和其它信息
- 將進程控制塊移到相應隊列即阻塞隊列或就緒隊列
- 選擇另一個進程執行
- 更新所選擇進程的 PCB 進程控制塊(包括將狀態變為運行態)
- 更新內存管理的數據結構
- 恢復第二個進程的上下文環境
進程調度算法
- 先來先服務調度算法
- 短作業優先調度算法
- 非搶占式優先級調度算法
- 搶占式優先級調度算法
- 高響應比優先調度算法
- 時間片輪轉法調度算法
進程間怎么通信
- 管道 (具名管道,無名管道)
- 消息隊列
- 信號:用於通知接收進程某個事件已經發生
- 信號量: 信號量是一個計數器,信號量用於實現進程間的互斥與同步,而不是用於存儲進程間通信數據
- 共享內存
- socket套接字
線程間通信
- 臨界區:通過多線程的串行化來訪問公共資源或一段代碼,速度快,適合控制數據訪問
- 互斥量 Synchronized/Lock:采用互斥對象機制,只有擁有互斥對象的線程才有訪問公共資源的權限。因為互斥對象只有一個,所以可以保證公共資源不會被多個線程同時訪問
- 信號量 Semphare:為控制具有有限數量的用戶資源而設計的,它允許多個線程在同一時刻去訪問同一個資源,但一般需要限制同一時刻訪問此資源的最大線程數目
- 事件(信號),Wait/Notify:通過通知操作的方式來保持多線程同步,還可以方便的實現多線程優先級的比較操作
LRU算法是如何實現的
volatile 內存屏障
volatile 關鍵字是一種類型修飾符,用它聲明的類型變量表示可以被某些編譯器未知的因素更改,比如:操作系統、硬件或者其它線程等。遇到這個關鍵字聲明的變量,編譯器對訪問該變量的代碼就不再進行優化,從而可以提供對特殊地址的穩定訪問。聲明時語法:int volatile vInt; 當要求使用 volatile 聲明的變量的值的時候,系統總是重新從它所在的內存讀取數據,即使它前面的指令剛剛從該處讀取過數據。而且讀取的數據立刻被保存
volatile 用在如下的幾個地方:
- 中斷服務程序中修改的供其它程序檢測的變量需要加 volatile
- 多任務環境下各任務間共享的標志應該加 volatile
- 存儲器映射的硬件寄存器通常也要加 volatile 說明,因為每次對它的讀寫都可能由不同意義
死鎖的四個條件和預防
- 互斥:一個資源每次只能被一個進程使用
- 不可搶占性: 當某個進程已經獲得這種資源后,系統是不能強行收回,其他進程也不能強行奪走,只能由自身使用完釋放
- 保持與等待:部分分配,允許進程在不釋放其已經分得的資源的情況下請求並等待分配別的資源
- 循環等待:若干個進程形成環形鏈
預防方法:
- 允許進程強行從占有者那里奪取某些資源,破壞不可搶占條件
- 進程在運行前一次性地向系統申請它所需要的全部資源。,破壞了保持與等待條件
- 把資源事先分類編號,按號分配,使進程在申請,占用資源時不會形成環路,破壞了
循環等待條件
銀行家算法
銀行家算法的基本思想是分配資源之前,判斷系統是否是安全的;若是,才分配。它是最具有代表性的避免死鎖的算法。
算法內容:
- 每一個線程進入系統時,它必須聲明在運行過程中,所需的每種資源類型最大數目,其數目不應超過系統所擁有每種資源總量,當線程請求一組資源系統必須確定有足夠資源分配給該進程,若有,再進一步計算這些資源分配給進程后,是否會使系統處於不安全狀態,不會(即若能在分配資源時找到一個安全序列),則將資源分配給它,否則等待
多路IO模型 NIO
在多路復用IO模型中,會有一個線程(Java中的Selector)不斷去輪詢多個socket的狀態,只有當socket真正有讀寫事件時,才真正調用實際的IO讀寫操作。因為在多路復用IO模型中,只需要使用一個線程就可以管理多個socket,系統不需要建立新的進程或者線程,也不必維護這些線程和進程,並且只有在真正有socket讀寫事件進行時,才會使用IO資源,所以它大大減少了資源占用。
五種IO模型
- 阻塞IO: 應用程序調用一個 IO 函數,導致應用程序阻塞,等待數據准備好
- 非阻塞IO: 我們把一個 SOCKET 接口設置為非阻塞就是告訴內核,當所請求的 I/O 操作
無法完成時,不要將進程睡眠,而是返回一個錯誤。這樣我們的 I/O 操作函數將不斷的測試數據是否已經准備好,如果沒有准備好,繼續測試,直到數據准備好為止。在這個不斷測試的過程中,會大量的占用 CPU 的時間 - 多路IO復用: I/O 復用模型會用到 select、poll、epoll 函數,這幾個函數也會使進程阻塞,但是和阻塞 I/O 所不同的的,這三個函數可以同時阻塞多個 I/O 操作。而且可以同時對多個讀操作,多個寫操作的 I/O 函數進行檢測,直到有數據可讀或可寫時,才真正調用 I/O 操作函數
- 信號驅動IO(不常用): 首先我們允許套接口進行信號驅動 I/O,並安裝一個信號處理函數,進程繼續運行並不阻塞。當數據准備好時,進程會收到一個 SIGIO 信號,可以在信號處理函數中調用 I/O操作函數處理數據。
- 異步IO: 當一個異步過程調用發出后,調用者不能立刻得到結果。實際處理這個調用的部件在完成后,通過狀態、通知和回調來通知調用者的輸入輸出操作
有哪幾種多路復用的方式?它們之間的區別
- select
- 單個進程能夠監視的文件描述符的數量存在最大限制,通常是 1024。由於 select 采用輪詢的方式掃描文件描述符,文件描述符數量越多,性能越差
- 內核/用戶空間內存拷貝問題,select 需要大量句柄數據結構,產生巨大開銷
- Select 返回的是含有整個句柄的數組,應用程序需要遍歷整個數組才能發現哪些句柄發生事件
- Select 的觸發方式是水平觸發,應用程序如果沒有完成對一個已經就緒的文件描述符進行 IO 操作,那么每次 select 調用還會將這些文件描述符通知進程
- poll
- 與 select 相比,poll 使用鏈表保存文件描述符,一沒有了監視文件數量的限制,但其他三個缺點依然存在
- epoll
- epoll 使用一個文件描述符管理多個描述符,將用戶關系的文件描述符的事件存放到內核的一個事件表中,這樣在用戶空間和內核空間的 copy 只需一次。Epoll 是事件觸發的,不是輪詢查詢的。沒有最大的並發連接限制,內存拷貝,利用 mmap() 文件映射內存加速與內核空間的消息傳遞
epoll的兩種工作模式
- LT模式
當 epoll_wait 檢測到描述符事件發生並將此事件通知應用程序,應用程序可以不立即處理該事件。下次調用 epoll_wait 時,會再次響應應用程序並通知此事件。一個 socket 第一次有數據,LT 模式下檢測到 socket 處於活躍狀態,接下來再有數據過來,接着觸發。或者說可以根據需要收取部分數據,只要 socket 上數據不收取完,epoll_wait 會接着返回這個可讀 socket。編程上如果需要數據包一部分一部分的處理,可以使用 LT 模式
- ET模式
當 epoll_wait 檢測到描述符事件發生並將此事件通知應用程序,應用程序必須立即處理該事件。如果不處理,下次調用 epoll_wait 時,不會再次響應應用程序並通知此事件。第一次有數據會觸發 socket,第二次再有數據不會觸發,必須等第一次的數據完全讀完或寫完。必須把當前 socket 數據全部收完,才能接受下一次的可讀 socket。編程上 ET 模式必須是一個循環,收取數據到 recv 返回-1,errno=EAGAIN
虛擬內存
-
虛擬內存使得應用程序認為它擁有連續的可用內存,這樣一來,就在邏輯層面上擴大了內存容量。但是實際上,只是把比較常用的內存片段取出來了而已,還有部分資源是放在磁盤存儲器上的。需要的時候再進行數據交換。
-
調度方式有,分頁式,段式,段頁式。比較流行方式是段頁式,他結合了前兩者的優點,以頁為單位替換,以段為單位使用。
-
常見的替換替換算法有4種,隨機算法,先進先出算法,LRU算法,最優算法。 比較常使用的是LRU算法,他在redis里也有使用,當redis的內存滿了的時候就是使用LRU算法替換掉舊內存。
算法
加密算法
線性同余法
快排的優化
打印二叉樹每一層,最右邊節點的值
尋找兩個鏈表的公共節點
鏡像二叉樹
刪除鏈表中所有值相等的節點
單例模式
雞蛋摔樓的問題
Linux
kill -9與kill -15的區別
- SIGNKILL(9) 的效果是立即殺死進程. 該信號不能被阻塞, 處理和忽略。
- SIGNTERM(15) 的效果是正常退出進程,退出前可以被阻塞或回調處理。並且它是Linux缺省的程序中斷信號(默認是15)。
- kill - 9 表示強制殺死該進程;與SIGTERM相比,這個信號不能被捕獲或忽略,同時接收這個信號的進程在收到這個信號時不能執行任何清理
Linux修改用戶權限
- 創建用戶
sudo password xxx # xxx 表示用戶名
- 刪除用戶
sudo userdel xxx sudo rm -rf /home/xxx # 刪除用戶權限相關配置 cd /home rm -rf xxx cat /etc/passwd # 找到最后一行,可以發現剛剛創建的用戶,再使用vi編輯器刪除最后一行 cat /etc/group # 找到最后一行,可以發現剛剛創建的用戶,再使用vi編輯器刪除最后一行 cd /var/spool/mail rm -rf xxx # 刪除郵箱文件
- 修改權限
# 采用修改系統中/etc/sudoers文件的方法分配用戶權限。因為此文件只有r權限,在改動前需要增加w權限,改動后,再去掉w權限 sudo chmod +w /etc/sudoers sudo vim /etc/sudoers # User privilege specification add text root ALL=(ALL:ALL) ALL xxx ALL=(ALL:ALL) ALL # 這一行為添加的代碼,XXX表示需要添加權限的用戶名 sudo chmod -w /etc/sudoers # 改為只讀模式
查看網絡端口
netstat -a #列出所有端口
netstat -at #列出所有tcp端口
netstat -au #列出所有udp端口
netstat -ax #列出所有UNIX端口
netstat -al #列出所有監聽中的端口
netstat -lt #列出所有監聽中的tcp有端口
netstat -lu #列出所有監聽中的udp端口
netstat -lx #列出所有監聽中的unix端口
查看所有文件的大小
du -h --max-depth=1 # 如果沒有--max-depth=1,則會遞歸顯示所有目錄
df 命令是查看文件系統給的大小
Git 版本控制
git rebase 與 git merge
-
Merge 會自動根據兩個分支的共同祖先和兩個分支的最新提交進行一個三方合並,然后將合並中修改的內容生成一個新的 commit,即 merge 合並兩個分支並生成一個新的提交,並且仍然后保存原來分支的 commit 記錄。
-
Rebase 會從兩個分支的共同祖先開始提取當前分支上的修改,然后將當前分支上的所有修改合並到目標分支的最新提交后面,如果提取的修改有多個,那 git 將依次應用到最新的提交后面。Rebase 后只剩下一個分支的 commit 記錄
