准備下蝦皮的面經(多為數據庫知識點+一些自己沒有掌握的知識點)


1.事務四大特性

原子性(Atomicity):事務中的所有操作作為一個整體像原子一樣不可分割,要么全部成功,要么全部失敗。

一致性(Consistency):事務的執行結果必須使數據庫從一個一致性狀態到另一個一致性狀態。一致性狀態是指:1.系統的狀態滿足數據的完整性約束(主碼,參照完整性,check約束等) 2.系統的狀態反應數據庫本應描述的現實世界的真實狀態,比如轉賬前后兩個賬戶的金額總和應該保持不變。

隔離性(Isolation):並發執行的事務不會相互影響,其對數據庫的影響和它們串行執行時一樣。比如多個用戶同時往一個賬戶轉賬,最后賬戶的結果應該和他們按先后次序轉賬的結果一樣。

持久性(Durability):事務一旦提交,其對數據庫的更新就是持久的。任何事務或系統故障都不會導致數據丟失。

事務舉例:

BEGIN TRANSACTION

A賬戶減少100元

B賬戶增加100元

COMMIT

  1.當數據庫操作失敗或者系統出現崩潰,系統能夠以事務為邊界進行恢復,不會出現A賬戶金額減少而B賬戶未增加的情況。

  2.當有多個用戶同時操作數據庫時,數據庫能夠以事務為單位進行並發控制,使多個用戶對B賬戶的轉賬操作相互隔離。

事務使系統能夠更方便的進行故障恢復以及並發控制,從而保證數據庫狀態的一致性

 2、常見並發異常

臟讀

臟讀又稱無效數據讀出(讀出了臟數據)。一個事務讀取另外一個事務還沒有提交的數據叫臟讀。

例如:事務T1修改了某個表中的一行數據,但是還沒有提交,這時候事務T2讀取了被事務T1修改后的數據,之后事務T1因為某種原因回滾(Rollback)了,那么事務T2讀取的數據就是臟的(無效的)。

解決辦法:把數據庫的事務隔離級別調整到READ_COMMITTED(讀提交/不可重復讀)

不可重復讀

不可重復讀是指在同一個事務內,兩次相同的查詢返回了不同的結果。

例如:事務T1會讀取兩次數據,在第一次讀取某一條數據后,事務T2修改了該數據並提交了事務,T1此時再次讀取該數據,兩次讀取便得到了不同的結果。

解決辦法:把數據庫的事務隔離級別調整到REPEATABLE_READ(可重復讀)

幻讀

幻讀也是指當事務不獨立執行時,插入或者刪除另一個事務當前影響的數據而發生的一種類似幻覺的現象。

例如:系統事務A將數據庫中所有數據都刪除的時候,但是事務B就在這個時候新插入了一條記錄,當事務A刪除結束后發現還有一條數據,就好像發生了幻覺一樣。這就叫幻讀。

解決辦法:把數據庫的事務隔離級別調整到SERIALIZABLE_READ(序列化執行),或者數據庫使用者自己進行加鎖來保證。  

3、事務的隔離級別

  1. 事務具有隔離性,理論上來說事務之間的執行不應該相互產生影響,其對數據庫的影響應該和它們串行執行時一樣。

  2. 然而完全的隔離性會導致系統並發性能很低,降低對資源的利用率,因而實際上對隔離性的要求會有所放寬,這也會一定程度造成對數據庫一致性要求降低

  3. SQL標准為事務定義了不同的隔離級別,從低到高依次是

  • 讀未提交(READ UNCOMMITTED)
  • 讀已提交(READ COMMITTED)
  • 可重復讀(REPEATABLE READ)
  • 串行化(SERIALIZABLE)

  事務的隔離級別越低,可能出現的並發異常越多,但是通常而言系統能提供的並發能力越強。不同的隔離級別與可能的並發異常的對應情況如下表所示,有一點需要強調,這種對應關系只是理論上的,對於特定的數據庫實現不一定准確,比如mysql的Innodb存儲引擎通過Next-Key Locking技術在可重復讀級別就消除了幻讀的可能。

  MySQL中默認事務隔離級別是“可重復讀”時並不會鎖住讀取到的行

  事務隔離級別:未提交讀時,寫數據只會鎖住相應的行。

  事務隔離級別為:可重復讀時,寫數據會鎖住整張表。

  事務隔離級別為:串行化時,讀寫數據都會鎖住整張表。

4、Mysql存儲引擎及他們的區別?

作者:瀟湘夜雨
鏈接:https://www.zhihu.com/question/20596402/answer/977935094
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

Innodb引擎概述

Innodb引擎提供了對數據庫ACID事務的支持,並且實現了SQL標准的四種隔離級別。該引擎還提供了行級鎖和外鍵約束,它的設計目標是處理大容量數據庫系統,它本身其實就是基於MySQL后台的完整數據庫系統,MySQL運行時Innodb會在內存中建立緩沖池,用於緩沖數據和索引。但是該引擎不支持FULLTEXT類型的索引,而且它沒有保存表的行數,當SELECT COUNT(*) FROM TABLE時需要掃描全表。當需要使用數據庫事務時,該引擎當然是首選。由於鎖的粒度更小,寫操作不會鎖定全表,所以在並發較高時,使用Innodb引擎會提升效率。但是使用行級鎖也不是絕對的,如果在執行一個SQL語句時MySQL不能確定要掃描的范圍,InnoDB表同樣會鎖全表。

MyISAM引擎概述

MyISAM是MySQL默認的引擎,但是它沒有提供對數據庫事務的支持,也不支持行級鎖和外鍵,因此當INSERT(插入)或UPDATE(更新)數據時即寫操作需要鎖定整個表,效率便會低一些。不過和Innodb不同,MyISAM中存儲了表的行數,於是SELECT COUNT(*) FROM TABLE時只需要直接讀取已經保存好的值而不需要進行全表掃描。如果表的讀操作遠遠多於寫操作且不需要數據庫事務的支持,那么MyISAM也是很好的選擇。

簡單介紹區別

1、MyISAM是非事務安全的,而InnoDB是事務安全的

2、MyISAM鎖的粒度是表級的,而InnoDB支持行級鎖

3、MyISAM支持全文類型索引,而InnoDB不支持全文索引

4、MyISAM相對簡單,效率上要優於InnoDB,小型應用可以考慮使用MyISAM

5、MyISAM表保存成文件形式,跨平台使用更加方便

6、查詢效率
  沒有where的count(*)使用MyISAM要比InnoDB快得多。因為MyISAM內置了一個計數器,count(*)時它直接從計數器中讀,而InnoDB必須掃描全表。所以在InnoDB上執行count(*)時一般要伴隨where,且where中要包含主鍵以外的索引列。為什么這里特別強調“主鍵以外”?因為InnoDB中primary index是和raw data存放在一起的,而secondary index則是單獨存放,然后有個指針指向primary key。所以只是count(*)的話使用secondary index掃描更快,而primary key則主要在掃描索引同時要返回raw data時的作用較大。MyISAM相對簡單,所以在效率上要優於InnoDB,小型應用可以考慮使用MyISAM。

  通過上述的分析,基本上可以考慮使用InnoDB來替代MyISAM引擎了,原因是InnoDB自身很多良好的特點,比如事務支持、存儲 過程、視圖、行級鎖定等等,在並發很多的情況下,相信InnoDB的表現肯定要比MyISAM強很多。另外,任何一種表都不是萬能的,只用恰當的針對業務類型來選擇合適的表類型,才能最大的發揮MySQL的性能優勢。如果不是很復雜的Web應用,非關鍵應用,還是可以繼續考慮MyISAM的,這個具體情況可以自己斟酌。

應用場景

1、MyISAM管理非事務表,提供高速存儲和檢索以及全文搜索能力,如果再應用中執行大量select操作,應該選擇MyISAM

2、InnoDB用於事務處理,具有ACID事務支持等特性,如果在應用中執行大量insert和update操作,應該選擇InnoDB

 

 5、MYISAM 和 INNODB索引的區別 以及如何實現的?

一 MyISAM索引實現

1. 主鍵索引

MyISAM引擎使用B+樹作為索引結果,葉節點的data域存放的是數據記錄的地址。下圖為MyISAM表的主索引,Col1為主鍵。

 

2. 輔助索引

在MyISAM中,主索引和輔助索引在結構上沒有任何區別,只是主索引要求key是唯一的,而輔助索引的key可以重復。下圖在Col2上建立一個輔助索引

同樣也是一顆B+Tree,data域保存數據記錄的地址。因此,MyISAM中索引檢索的算法為首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,則取出其data域的值,然后以data域的值為地址,讀取相應數據記錄。

MyISAM的索引方式也叫做“非聚集”的,之所以這么稱呼是為了與InnoDB的聚集索引區分。

二 InnoDB索引實現

1 主鍵索引

同樣是B+樹,實現方式卻完全不同。InnoDB表數據文件本身就是一個索引結構,樹的葉節點data域保存了完整的數據記錄,這種索引叫做聚集索引

 因為InnoDB的數據文件本身要按主鍵聚集,所以InnoDB要求表必須有主鍵(MyISAM可以沒有),如果沒有顯式指定,則mysql會自動選擇一個可以唯一標識數據記錄的列作為主鍵。如果不存在這種列,則mysql自動為InnoDB表生成一個隱含字段作為主鍵,這個字段長度為6個字節,類型為長整型。

 

2 輔助索引

  InnoDB的所有輔助索引都引用主鍵作為data域。下圖為定義在Col3上的一個輔助索引

因此InnoDB 的索引能提供一種非常快速的主鍵查找性能。不過,它的輔助索引也會包含主鍵列,所以如果主鍵定義的比較大,其他索引也將很大。InnoDB 不會壓縮索引。

聚集索引這種實現方式使得按主鍵的搜索十分高效,但是輔助索引搜索需要檢索兩遍索引:首先檢索輔助索引獲得主鍵,然后用主鍵到主索引中檢索獲得記錄。

不同存儲引擎的索引實現方式對於正確使用和優化索引都非常有幫助,例如知道了InnoDB的索引實現后,就很容易明白為什么不建議使用過長的字段作為主鍵,因為所有輔助索引都引用主索引,過長的主索引會令輔助索引變得過大。再例如,用非單調的字段作為主鍵在InnoDB中不是個好主意,因為InnoDB數據文件本身是一顆B+Tree,非單調的主鍵會造成在插入新記錄時數據文件為了維持B+Tree的特性而頻繁的分裂調整,十分低效,而使用自增字段作為主鍵則是一個很好的選擇。

三 InnoDB索引MyISAM索引的區別

1 存儲結構(主索引/輔助索引)

InnoDB的數據文件本身就是主索引文件。而MyISAM的主索引和數據是分開的。

InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址。而MyISAM的輔助索引和主索引沒有多大區別。

innoDB是聚簇索引,數據掛在逐漸索引之下。

2 鎖

MyISAM使用的是表鎖

InnoDB使用行鎖

3 事務

MyISAM沒有事務支持和MVCC

InnoDB支持事務和MVCC

4 全文索引

MyISAM支持FULLTEXT類型的全文索引

InnoDB不支持FULLTEXT類型的全文索引,但是InnoDB可以使用sphinx插件支持全文索引,並且效果更好

5 主鍵

MyISAM允許沒有任何索引和主鍵的表存在,索引都是保存行的地址

InnoDB如果沒有設定主鍵或非空唯一索引,就會自動生成一個6字節的主鍵,數據是主索引的一部分,附加索引保存的是主索引的值

6 外鍵

 MyISAM不支持

InnoDB支持

6、哈希索引 b+索引 

b+索引:

B+樹是一個平衡的多叉樹,從根節點到每個葉子節點的高度差值不超過1,而且同層級的節點間有指針相互鏈接。

在B+樹上的常規檢索,從根節點到葉子節點的搜索效率基本相當,不會出現大幅波動,而且基於索引的順序掃描時,也可以利用雙向指針快速左右移動,效率非常高。

 

哈希索引:

哈希索引就是采用一定的哈希算法,把鍵值換算成新的哈希值,檢索時不需要類似B+樹那樣從根節點到葉子節點逐級查找,只需一次哈希算法即可立刻定位到相應的位置,速度非常快。

 

B+樹索引和哈希索引的明顯區別是:

  • 如果是等值查詢,那么哈希索引明顯有絕對優勢,因為只需要經過一次算法即可找到相應的鍵值;當然了,這個前提是,鍵值都是唯一的。如果鍵值不是唯一的,就需要先找到該鍵所在位置,然后再根據鏈表往后掃描,直到找到相應的數據;

  • 從示意圖中也能看到,如果是范圍查詢檢索,這時候哈希索引就毫無用武之地了,因為原先是有序的鍵值,經過哈希算法后,有可能變成不連續的了,就沒辦法再利用索引完成范圍查詢檢索;

  • 同理,哈希索引也沒辦法利用索引完成排序,以及like ‘xxx%’ 這樣的部分模糊查詢(這種部分模糊查詢,其實本質上也是范圍查詢);

  • 哈希索引也不支持多列聯合索引的最左匹配規則

  • B+樹索引的關鍵字檢索效率比較平均,不像B樹那樣波動幅度大,在有大量重復鍵值情況下,哈希索引的效率也是極低的,因為存在所謂的哈希碰撞問題

7、數據庫中索引和主鍵的區別

索引用來快速地尋找那些具有特定值的記錄。

 索引與主鍵的主要區別有
主鍵是一種約束,唯一索引是一種索引,兩者在本質上是不同的。

主鍵創建后一定包含一個唯一性索引,唯一性索引並不一定就是主鍵。

唯一性索引列允許空值,而主鍵列不允許為空值。

主鍵列在創建時,已經默認為空值 + 唯一索引了。

主鍵可以被其他表引用為外鍵,而唯一索引不能。

一個表最多只能創建一個主鍵,但可以創建多個唯一索引。

主鍵更適合那些不容易更改的唯一標識,如自動遞增列、身份證號等。

8、聚集索引以及使用條件

非聚集索引和聚集索引一樣, 同樣是采用平衡樹作為索引的數據結構。索引樹結構中各節點的值來自於表中的索引字段, 假如給user表的name字段加上索引 , 那么索引就是由name字段中的值構成,在數據改變時, DBMS需要一直維護索引結構的正確性。如果給表中多個字段加上索引 , 那么就會出現多個獨立的索引結構,每個索引(非聚集索引)互相之間不存在關聯。

每次給字段建一個新索引, 字段中的數據就會被復制一份出來, 用於生成索引。 因此, 給表添加索引,會增加表的體積, 占用磁盤存儲空間。所以索引不是建立越多越好的。

非聚集索引和聚集索引的區別在於, 通過聚集索引可以查到需要查找的數據, 而通過非聚集索引可以查到記錄對應的主鍵值 , 再使用主鍵的值通過聚集索引查找到需要的數據,如下圖

 

9、數據庫中join的inner join, outer join, cross join

1.以A,B兩張表為例
A left join B
選出A的所有記錄,B表中沒有的以null 代替
right join 同理

2.inner join
A,B的所有記錄都選出,沒有的記錄以null代替

3.cross join (笛卡爾積)
A中的每一條記錄和B中的每一條記錄生成一條記錄
例如A中有4條,B中有4條,cross join 就有16條記錄

10、有哪些鎖,select時怎么加排它鎖

概念
樂觀鎖 自己實現,通過版本號
悲觀鎖 共享鎖,多個事務,只能讀不能寫,加 lock in share mode
排它鎖 一個事務,只能寫,for update
行鎖 作用於數據行
表鎖 作於用表

11、最左匹配原則

最左匹配原則是針對索引的
舉例來說:兩個字段(name,age)建立聯合索引,如果where age=12這樣的話,是沒有利用到索引的,
這里我們可以簡單的理解為先是對name字段的值排序,然后對age的數據排序,如果直接查age的話,這時就沒有利用到索引了,
查詢條件where name=‘xxx’ and age=xx 這時的話,就利用到索引了,再來思考下where age=xx and name=’xxx‘ 這個sql會利用索引嗎,
按照正常的原則來講是不會利用到的,但是優化器會進行優化,把位置交換下。這個sql也能利用到索引了

12、redis底層結構  為什么快 跳表具體應用在那些場景

https://www.cnblogs.com/ysocean/p/9080942.html

跳躍表在 Redis 中不如鏈表和字典等數據結構的應用廣泛,只有兩個地方用到。一是實現有序集合鍵,另一個是在集群節點中用作內部數據結構。 

Redis為什么這么快?

1、完全基於內存,絕大部分請求是純粹的內存操作,非常快速。數據存在內存中,類似於HashMap,HashMap的優勢就是查找和操作的時間復雜度都是O(1);

2、數據結構簡單,對數據操作也簡單,Redis中的數據結構是專門進行設計的;

3、采用單線程,避免了不必要的上下文切換和競爭條件,也不存在多進程或者多線程導致的切換而消耗 CPU,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有因為可能出現死鎖而導致的性能消耗;

4、使用多路I/O復用模型,非阻塞IO;

5、使用底層模型不同,它們之間底層實現方式以及與客戶端之間通信的應用協議不一樣,Redis直接自己構建了VM 機制 ,因為一般的系統調用系統函數的話,會浪費一定的時間去移動和請求;

 其他數據庫的問題

1.數據庫的主從復制

主從復制的幾種方式:

同步復制:

所謂的同步復制,意思是master的變化,必須等待slave-1,slave-2,...,slave-n完成后才能返回。 這樣,顯然不可取,也不是MySQL復制的默認設置。比如,在WEB前端頁面上,用戶增加了條記錄,需要等待很長時間。

異步復制:

如同AJAX請求一樣。master只需要完成自己的數據庫操作即可。至於slaves是否收到二進制日志,是否完成操作,不用關心,MySQL的默認設置。

半同步復制:

master只保證slaves中的一個操作成功,就返回,其他slave不管。 這個功能,是由google為MySQL引入的。

2.數據庫主從復制分析的 7 個問題?

問題1:master的寫操作,slaves被動的進行一樣的操作,保持數據一致性,那么slave是否可以主動的進行寫操作?

假設slave可以主動的進行寫操作,slave又無法通知master,這樣就導致了master和slave數據不一致了。因此slave不應該進行寫操作,至少是slave上涉及到復制的數據庫不可以寫。實際上,這里已經揭示了讀寫分離的概念。

問題2:主從復制中,可以有N個slave,可是這些slave又不能進行寫操作,要他們干嘛?

實現數據備份:
類似於高可用的功能,一旦master掛了,可以讓slave頂上去,同時slave提升為master。

異地容災:比如master在北京,地震掛了,那么在上海的slave還可以繼續。
主要用於實現scale out,分擔負載,可以將讀的任務分散到slaves上。
【很可能的情況是,一個系統的讀操作遠遠多於寫操作,因此寫操作發向master,讀操作發向slaves進行操作】

問題3:主從復制中有master,slave1,slave2,...等等這么多MySQL數據庫,那比如一個JAVA WEB應用到底應該連接哪個數據庫?

我們在應用程序中可以這樣,insert/delete/update這些更新數據庫的操作,用connection(for master)進行操作,

select用connection(for slaves)進行操作。那我們的應用程序還要完成怎么從slaves選擇一個來執行select,例如使用簡單的輪循算法。

這樣的話,相當於應用程序完成了SQL語句的路由,而且與MySQL的主從復制架構非常關聯,一旦master掛了,某些slave掛了,那么應用程序就要修改了。能不能讓應用程序與MySQL的主從復制架構沒有什么太多關系呢?
找一個組件,application program只需要與它打交道,用它來完成MySQL的代理,實現SQL語句的路由。
MySQL proxy並不負責,怎么從眾多的slaves挑一個?可以交給另一個組件(比如haproxy)來完成。

這就是所謂的MySQL READ WRITE SPLITE,MySQL的讀寫分離。

問題4:如果MySQL proxy , direct , master他們中的某些掛了怎么辦?

總統一般都會弄個副總統,以防不測。同樣的,可以給這些關鍵的節點來個備份。

問題5:當master的二進制日志每產生一個事件,都需要發往slave,如果我們有N個slave,那是發N次,還是只發一次?如果只發一次,發給了slave-1,那slave-2,slave-3,...它們怎么辦?

顯 然,應該發N次。實際上,在MySQL master內部,維護N個線程,每一個線程負責將二進制日志文件發往對應的slave。master既要負責寫操作,還的維護N個線程,負擔會很重。可以這樣,slave-1是master的從,slave-1又是slave-2,slave-3,...的主,同時slave-1不再負責select。 slave-1將master的復制線程的負擔,轉移到自己的身上。這就是所謂的多級復制的概念。

問題6:當一個select發往MySQL proxy,可能這次由slave-2響應,下次由slave-3響應,這樣的話,就無法利用查詢緩存了。

應該找一個共享式的緩存,比如memcache來解決。將slave-2,slave-3,...這些查詢的結果都緩存至mamcache中。

問題7:隨着應用的日益增長,讀操作很多,我們可以擴展slave,但是如果master滿足不了寫操作了,怎么辦呢?

scale on ?更好的服務器? 沒有最好的,只有更好的,太貴了。。。
scale out ? 主從復制架構已經滿足不了。
可以分庫【垂直拆分】,分表【水平拆分】。

3.mysql 高並發環境解決方案?

MySQL 高並發環境解決方案: 分庫 分表 分布式 增加二級緩存。。。。。

需求分析:互聯網單位 每天大量數據讀取,寫入,並發性高。

現有解決方式:水平分庫分表,由單點分布到多點數據庫中,從而降低單點數據庫壓力。

集群方案:解決DB宕機帶來的單點DB不能訪問問題。

讀寫分離策略:極大限度提高了應用中Read數據的速度和並發量。無法解決高寫入壓力。

4.數據庫崩潰時事務的恢復機制(REDO日志和UNDO日志)?

轉載:MySQL REDO日志和UNDO日志

Undo Log:

Undo Log是為了實現事務的原子性,在MySQL數據庫InnoDB存儲引擎中,還用了Undo Log來實現多版本並發控制(簡稱:MVCC)。

事務的原子性(Atomicity)事務中的所有操作,要么全部完成,要么不做任何操作,不能只做部分操作。如果在執行的過程中發生了錯誤,要回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過。
原理Undo Log的原理很簡單,為了滿足事務的原子性,在操作任何數據之前,首先將數據備份到一個地方(這個存儲數據備份的地方稱為UndoLog)。然后進行數據的修改。如果出現了錯誤或者用戶執行了ROLLBACK語句,系統可以利用Undo Log中的備份將數據恢復到事務開始之前的狀態。

之所以能同時保證原子性和持久化,是因為以下特點:

更新數據前記錄Undo log。
為了保證持久性,必須將數據在事務提交前寫到磁盤。只要事務成功提交,數據必然已經持久化。
Undo log必須先於數據持久化到磁盤。如果在G,H之間系統崩潰,undo log是完整的, 可以用來回滾事務。
如果在A-F之間系統崩潰,因為數據沒有持久化到磁盤。所以磁盤上的數據還是保持在事務開始前的狀態。

缺陷:每個事務提交前將數據和Undo Log寫入磁盤,這樣會導致大量的磁盤IO,因此性能很低。
如果能夠將數據緩存一段時間,就能減少IO提高性能。但是這樣就會喪失事務的持久性。因此引入了另外一種機制來實現持久化,即Redo Log。

Redo Log:

原理和Undo Log相反,Redo Log記錄的是新數據的備份。在事務提交前,只要將Redo Log持久化即可,不需要將數據持久化。當系統崩潰時,雖然數據沒有持久化,但是Redo Log已經持久化。系統可以根據Redo Log的內容,將所有數據恢復到最新的狀態。

操作系統部分

1、進程、線程、協程區別

協程,是一種比線程更加輕量級的存在,協程不是被操作系統內核所管理,而完全是由程序所控制(也就是在用戶態執行)。這樣帶來的好處就是性能得到了很大的提升,不會像線程切換那樣消耗資源。

子程序,或者稱為函數,在所有語言中都是層級調用,比如A調用B,B在執行過程中又調用了C,C執行完畢返回,B執行完畢返回,最后是A執行完畢。所以子程序調用是通過棧實現的,一個線程就是執行一個子程序。子程序調用總是一個入口,一次返回,調用順序是明確的。而協程的調用和子程序不同。

協程在子程序內部是可中斷的,然后轉而執行別的子程序,在適當的時候再返回來接着執行。

協程的特點在於是一個線程執行,那和多線程比,協程有何優勢?

極高的執行效率:因為子程序切換不是線程切換,而是由程序自身控制,因此,沒有線程切換的開銷,和多線程比,線程數量越多,協程的性能優勢就越明顯;

不需要多線程的鎖機制:因為只有一個線程,也不存在同時寫變量沖突,在協程中控制共享資源不加鎖,只需要判斷狀態就好了,所以執行效率比多線程高很多

2、進程使用的狀態怎么查看

   ps -l   列出與本次登錄有關的進程信息;
   ps -aux   查詢內存中進程信息;
   ps -aux | grep ***   查詢***進程的詳細信息;
   top   查看內存中進程的動態信息;
   kill -9 pid   殺死進程。

3、進程通信方式

管道,消息隊列,共享內存,信號量,socket,信號,文件鎖

4、進程調度算法

先來先服務調度算法是一種最簡單的調度算法,也稱為先進先出或嚴格排隊方案。當每個進程就緒后,它加入就緒隊列。當前正運行的進程停止執行,選擇在就緒隊列中存在時間最長的進程運行。該算法既可以用於作業調度,也可以用於進程調度。先來先去服務比較適合於常作業(進程),而不利於段作業(進程)

時間片輪轉調度算法主要適用於分時系統。在這種算法中,系統將所有就緒進程按到達時間的先后次序排成一個隊列,進程調度程序總是選擇就緒隊列中第一個進程執行,即先來先服務的原則,但僅能運行一個時間片,如100ms。在使用完一個時間片后,即使進程並未完成其運行,它也必須釋放出(被剝奪)處理機給下一個就緒的進程,而被剝奪的進程返回到就緒隊列的末尾重新排隊,等候再次運行。

優先級調度算法又稱優先權調度算法,該算法既可以用於作業調度,也可以用於進程調度,該算法中的優先級用於描述作業運行的緊迫程度

多級反饋隊列算法,不必事先知道各種進程所需要執行的時間,他是當前被公認的一種較好的進程調度算法。

多級反饋隊列調度算法的實現思想如下:

  1. 應設置多個就緒隊列,並為各個隊列賦予不同的優先級,第1級隊列的優先級最高,第2級隊列次之,其余隊列的優先級逐次降低。
  2. 賦予各個隊列中進程執行時間片的大小也各不相同,在優先級越高的隊列中,每個進程的運行時間片就越小。例如,第2級隊列的時間片要比第1級隊列的時間片長一倍, ……第i+1級隊列的時間片要比第i級隊列的時間片長一倍。
  3. 當一個新進程進入內存后,首先將它放入第1級隊列的末尾,按FCFS原則排隊等待調度。當輪到該進程執行時,如它能在該時間片內完成,便可准備撤離系統;如果它在一個時間片結束時尚未完成,調度程序便將該進程轉入第2級隊列的末尾,再同樣地按FCFS 原則等待調度執行;如果它在第2級隊列中運行一個時間片后仍未完成,再以同樣的方法放入第3級隊列……如此下去,當一個長進程從第1級隊列依次降到第 n 級隊列后,在第 n 級隊列中便釆用時間片輪轉的方式運行。
  4. 僅當第1級隊列為空時,調度程序才調度第2級隊列中的進程運行;僅當第1 ~ (i-1)級隊列均為空時,才會調度第i級隊列中的進程運行。如果處理機正在執行第i級隊列中的某進程時,又有新進程進入優先級較高的隊列(第 1 ~ (i-1)中的任何一個隊列),則此時新進程將搶占正在運行進程的處理機,即由調度程序把正在運行的進程放回到第i級隊列的末尾,把處理機分配給新到的更高優先級的進程。

多級反饋隊列的優勢有:

    • 終端型作業用戶:短作業優先。
      • 短批處理作業用戶:周轉時間較短。
      • 長批處理作業用戶:經過前面幾個隊列得到部分執行,不會長期得不到處理。

5、多線程同步方式

線程同步是指線程之間所具有的一種制約關系,一個線程的執行依賴另一個線程的消息,當它沒有得到另一個線程的消息時應等待,直到消息到達時才被喚醒。

  1. 臨界區
  2. 信號量
  3. 事件
  4. 互斥量

臨界區(Critical Section)是一段獨占對某些共享資源訪問的代碼,在任意時刻只允許一個線程對共享資源進行訪問。如果有多個線程試圖同時訪問臨界區,那么在有一個線程進入后其他所有試圖訪問此臨界區的線程將被掛起,並一直持續到進入臨界區的線程離開。臨界區在被釋放后,其他線程可以繼續搶占,並以此達到用原子方式操作共享資源的目的。

事件(Event)是WIN32提供的最靈活的線程間同步方式,事件可以處於激發狀態(signaled or true)或未激發狀態(unsignal or false)。根據狀態變遷方式的不同,事件可分為兩類: 
(1)手動設置:這種對象只可能用程序手動設置,在需要該事件或者事件發生時,采用SetEvent及ResetEvent來進行設置。 
(2)自動恢復:一旦事件發生並被處理后,自動恢復到沒有事件狀態,不需要再次設置。

信號量是維護0到指定最大值之間的同步對象。信號量狀態在其計數大於0時是有信號的,而其計數是0時是無信號的。信號量對象在控制上可以支持有限數量共享資源的訪問。

信號量的特點和用途可用下列幾句話定義: 
(1)如果當前資源的數量大於0,則信號量有效; 
(2)如果當前資源數量是0,則信號量無效; 
(3)系統決不允許當前資源的數量為負值; 
(4)當前資源數量決不能大於最大資源數量。

互斥量:采用互斥對象機制。 只有擁有互斥對象的線程才有訪問公共資源的權限,因為互斥對象只有一個,所以能保證公共資源不會同時被多個線程訪問。互斥不僅能實現同一應用程序的公共資源安全共享,還能實現不同應用程序的公共資源安全共享。

6、進程性能分析工具vmstat

 

7、socket套接字通信用的函數

 

8、C++內存分布

9、select poll epoll

 https://www.cnblogs.com/sky-heaven/p/7011684.html

計算機網絡部分

1、tcp、ip頭部結構

 

 

 

 tcp報文頭部

 

ip頭部

 

 

 

 

2、三次握手四次握手的狀態 為什么這么設定

主機A(client)和主機B(server)開始建立握手過程:

第一次握手:主機A發送位碼為syn=1,隨機產生seq number=10001的數據包到服務器,主機B由SYN=1知道,A要求建立聯機,此時狀態為SYN_SENT;
第二次握手:主機B收到請求后要確認聯機信息,向A發送ack number=(主機A的seq+1),syn=1,ack=1,隨機產生seq=20001的包,此時狀態由LISTEN變為SYN_RECV;
第三次握手:主機A收到后檢查ack number是否正確,即第一次發送的seq number+1,以及位碼ack是否為1,若正確,主機A會再發送ack number=(主機B的seq+1),ack=1,主機B收到后確認seq值與ack=1則連接建立成功,雙方狀態ESTABLISHED。

完成三次握手,主機A與主機B開始傳送數據。

解釋各狀態的含意:
CLOSED: 這個沒什么好說的了,表示初始狀態。 
LISTEN: 這個也是非常容易理解的一個狀態,表示服務器端的某個SOCKET處於監聽狀態,可以接受連接了。 
SYN_RECV: 這個狀態表示接受到了SYN報文,在正常情況下,這個狀態是服務器端的SOCKET在建立TCP連接時的三次握手會話過程中的一個中間狀態,很短暫,基本 上用netstat你是很難看到這種狀態的,除非你特意寫了一個客戶端測試程序,故意將三次TCP握手過程中最后一個ACK報文不予發送。因此這種狀態 時,當收到客戶端的ACK報文后,它會進入到ESTABLISHED狀態。 
SYN_SENT: 這個狀態與SYN_RECV遙想呼應,當客戶端SOCKET執行CONNECT連接時,它首先發送SYN報文,因此也隨即它會進入到了SYN_SENT狀 態,並等待服務端的發送三次握手中的第2個報文。SYN_SENT狀態表示客戶端已發送SYN報文。 
ESTABLISHED:這個容易理解了,表示連接已經建立了。 

 

 

 TCP的連接的拆除需要發送四個包,因此稱為四次揮手(four-way handshake)。客戶端或服務器均可主動發起揮手動作。
解析各種狀態含義:
FIN_WAIT_1: 這個狀態要好好解釋一下,其實FIN_WAIT_1和FIN_WAIT_2狀態的真正含義都是表示等待對方的FIN報文。而這兩種狀態的區別 是:FIN_WAIT_1狀態實際上是當SOCKET在ESTABLISHED狀態時,它想主動關閉連接,向對方發送了FIN報文,此時該SOCKET即 進入到FIN_WAIT_1狀態。而當對方回應ACK報文后,則進入到FIN_WAIT_2狀態,當然在實際的正常情況下,無論對方何種情況下,都應該馬 上回應ACK報文,所以FIN_WAIT_1狀態一般是比較難見到的,而FIN_WAIT_2狀態還有時常常可以用netstat看到。 
FIN_WAIT_2:上面已經詳細解釋了這種狀態,實際上FIN_WAIT_2狀態下的SOCKET,表示半連接,也即有一方要求close連接,但另外還告訴對方,我暫時還有點數據需要傳送給你,稍后再關閉連接。 
TIME_WAIT: 表示收到了對方的FIN報文,並發送出了ACK報文,就等2MSL后即可回到CLOSED可用狀態了。如果FIN_WAIT_1狀態下,收到了對方同時帶 FIN標志和ACK標志的報文時,可以直接進入到TIME_WAIT狀態,而無須經過FIN_WAIT_2狀態。 
CLOSING: 這種狀態比較特殊,實際情況中應該是很少見,屬於一種比較罕見的例外狀態。正常情況下,當你發送FIN報文后,按理來說是應該先收到(或同時收到)對方的 ACK報文,再收到對方的FIN報文。但是CLOSING狀態表示你發送FIN報文后,並沒有收到對方的ACK報文,反而卻也收到了對方的FIN報文。什 么情況下會出現此種情況呢?其實細想一下,也不難得出結論:那就是如果雙方幾乎在同時close一個SOCKET的話,那么就出現了雙方同時發送FIN報 文的情況,也即會出現CLOSING狀態,表示雙方都正在關閉SOCKET連接。 
CLOSE_WAIT: 這種狀態的含義其實是表示在等待關閉。怎么理解呢?當對方close一個SOCKET后發送FIN報文給自己,你系統毫無疑問地會回應一個ACK報文給對 方,此時則進入到CLOSE_WAIT狀態。接下來呢,實際上你真正需要考慮的事情是察看你是否還有數據發送給對方,如果沒有的話,那么你也就可以 close這個SOCKET,發送FIN報文給對方,也即關閉連接。所以你在CLOSE_WAIT狀態下,需要完成的事情是等待你去關閉連接。 
LAST_ACK: 這個狀態還是比較容易好理解的,它是被動關閉一方在發送FIN報文后,最后等待對方的ACK報文。當收到ACK報文后,也即可以進入到CLOSED可用狀態了。 

3、三次握手的隱患  洪泛攻擊

1)SYN flood 泛洪攻擊 , 偽裝的IP向服務器發送一個SYN請求建立連接,然后服務器向該IP回復SYN和ACK,但是找不到該IP對應的主機,當超時時服務器收不到ACK會重復發送。當大量的攻擊者請求建立連接時,服務器就會存在大量未完成三次握手的連接,服務器主機backlog被耗盡而不能響應其它連接。即SYN flood泛洪攻擊 
  防范措施: 
  1、降低SYN timeout時間,使得主機盡快釋放半連接的占用 
  2、采用SYN cookie設置,如果短時間內連續收到某個IP的重復SYN請求,則認為受到了該IP的攻擊,丟棄來自該IP的后續請求報文 
  3、在網關處設置過濾,拒絕將一個源IP地址不屬於其來源子網的包進行更遠的路由 
2)Land 攻擊 , 當一個主機向服務器發送SYN請求連接,服務器回復ACK和SYN后,攻擊者截獲ACK和SYN。然后偽裝成原始主機繼續與服務器進行通信 , 目標地址和源地址都是目標本身,自己聯系自己

這類攻擊的檢測方法相對來說比較容易,因為可以直接通過判斷網絡數據包的源地址和目標地址是否相同確認是否屬於攻擊行為。

4、tcp可靠性的保證

ack 流量控制 擁塞控制等等

5、time_wait的原理

在TCP連接中,當被動關閉連接的一方(圖中client)發送的FIN報文到達時,被動關閉連接的一方會發送ACK確認報文,並且進入TIME_WAIT狀態,並且等待2MSL時間段(MSL:maximum segment life)。這么做有下述兩個原因:

  1. 被動關閉連接的一方(圖中的server)在一段時間內沒有收到對方的ACK確認數據包,會重新發送FIN數據包,因而主動關閉連接的一方需要停留在等待狀態以處理對方重新發送的FIN數據包。否則他會回應一個RST數據包給被動關閉連接的一方,使得對方莫名其妙。

  2. 在TIME_WAIT狀態下,不允許應用程序在當前ip和端口上和之前通信的client(這個client的ip和端口號不變)建立一個新的連接。這樣就能避免新的連接收到之前的ip和端口一致的連接殘存在網絡中的數據包。這也是TIME_WAIT狀態的等待時間被設置為2MSL的原因,以確保網絡上當前連接兩個方向上尚未接收的TCP報文已經全部消失

6、http協議特點

HTTP 是一個屬於應用層的面向對象的協議,HTTP 協議一共有五大特點:1、支持客戶/服務器模式;2、簡單快速;3、靈活;4、無連接;5、無狀態

簡單快速:客戶向服務器請求服務時,只需傳送請求方法和路徑。請求方法常用的有GET、HEAD、POST。每種方法規定了客戶與服務器聯系的類型不同。由於HTTP協議簡單,使得HTTP服務器的程序規模小,因而通信速度很快。

靈活:HTTP允許傳輸任意類型的數據對象。正在傳輸的類型由Content-Type(Content-Type是HTTP包中用來表示內容類型的標識)加以標記。

無連接的含義是限制每次連接只處理一個請求。服務器處理完客戶的請求,並收到客戶的應答后,即斷開連接。采用這種方式可以節省傳輸時間。Keep-Alive 功能使客戶端到服務器端的連接持續有效,當出現對服務器的后繼請求時,Keep-Alive 功能避免了建立或者重新建立連接。

無狀態是指協議對於事務處理沒有記憶能力,服務器不知道客戶端是什么狀態。即我們給服務器發送 HTTP 請求之后,服務器根據請求,會給我們發送數據過來,但是,發送完,不會記錄任何信息。

Cookie可以保持登錄信息到用戶下次與服務器的會話,換句話說,下次訪問同一網站時,用戶會發現不必輸入用戶名和密碼就已經登錄了。當客戶端訪問服務器時,服務器根據需求設置 Session,將會話信息保存在服務器上,同時將標示 Session 的 SessionId 傳遞給客戶端瀏覽器,瀏覽器將這個 SessionId 保存在內存中,我們稱之為無過期時間的 Cookie。

7、https協議解釋  加密ssl具體細節

https://blog.csdn.net/gogzf/article/details/78385487

8、http頭部結構

一個HTTP請求由四個部分組成:請求行、請求頭部、空行、請求數據

請求頭部:HTTP客戶程序(例如瀏覽器),向服務器發送請求的時候必須指明請求類型(一般是GET或者 POST)。

響應報文由三部分組成:響應行、響應頭、空行、響應體

響應頭用於描述服務器的基本信息,以及數據的描述,服務器通過這些數據的描述信息,可以通知客戶端如何處理等一會兒它回送的數據。設置HTTP響應頭往往和狀態碼結合起來

9、cookie session的區別

上面有提到過

10.http狀態碼

200 OK:表示從客戶端發送給服務器的請求被正常處理並返回;

204 No Content:表示客戶端發送給客戶端的請求得到了成功處理,但在返回的響應報文中不含實體的主體部分(沒有資源可以返回);

206 Patial Content:表示客戶端進行了范圍請求,並且服務器成功執行了這部分的GET請求,響應報文中包含由Content-Range指定范圍的實體內容。

3xx (5種)

301 Moved Permanently:永久性重定向,表示請求的資源被分配了新的URL,之后應使用更改的URL;

302 Found:臨時性重定向,表示請求的資源被分配了新的URL,希望本次訪問使用新的URL;

       301與302的區別:前者是永久移動,后者是臨時移動(之后可能還會更改URL)

303 See Other:表示請求的資源被分配了新的URL,應使用GET方法定向獲取請求的資源;

      302與303的區別:后者明確表示客戶端應當采用GET方式獲取資源

304 Not Modified:表示客戶端發送附帶條件(是指采用GET方法的請求報文中包含if-Match、If-Modified-Since、If-None-Match、If-Range、If-Unmodified-Since中任一首部)的請求時,服務器端允許訪問資源,但是請求為滿足條件的情況下返回改狀態碼;

307 Temporary Redirect:臨時重定向,與303有着相同的含義,307會遵照瀏覽器標准不會從POST變成GET;(不同瀏覽器可能會出現不同的情況);

4xx (4種)

400 Bad Request:表示請求報文中存在語法錯誤;

401 Unauthorized:未經許可,需要通過HTTP認證;

403 Forbidden:服務器拒絕該次訪問(訪問權限出現問題)

404 Not Found:表示服務器上無法找到請求的資源,除此之外,也可以在服務器拒絕請求但不想給拒絕原因時使用;

5xx (2種)

500 Inter Server Error:表示服務器在執行請求時發生了錯誤,也有可能是web應用存在的bug或某些臨時的錯誤時;

503 Server Unavailable:表示服務器暫時處於超負載或正在進行停機維護,無法處理請求;

11、get post delete put

1、GET

get請求是用來獲取數據的,只是用來查詢數據,不對服務器的數據做任何的修改,新增,刪除等操作。

在這里我們認為get請求是安全的,以及冪等的。安全就是指不影響服務器的數據,冪等是指同一個請求發送多次返回的結果應該相同。

特點:

get請求會把請求的參數附加在URL后面,這樣會產生安全問題,如果是系統的登陸接口采用的get請求,需要對請求的參數做一個加密。

get請求其實本身HTTP協議並沒有限制它的URL大小,但是不同的瀏覽器對其有不同的大小長度限制

2、POST

post請求一般是對服務器的數據做改變,常用來數據的提交,新增操作。

特點:

post請求的請求參數都是請求體中

post請求本身HTTP協議也是沒有限制大小的,限制它的是服務器的處理能力

3、PUT

put請求與post一樣都會改變服務器的數據,但是put的側重點在於對於數據的修改操作,但是post側重於對於數據的增加。

4、DELETE

delete請求用來刪除服務器的資源。

5、OPTIONS

options請求屬於瀏覽器的預檢請求,查看服務器是否接受請求,預檢通過后,瀏覽器才會去發get,post,put,delete等請求。至於什么情況下瀏覽器會發預檢請求,瀏覽器會會將請求分為兩類,簡單請求與非簡單請求,非簡單請求會產生預檢options請求。

12、url到頁面渲染完成的狀態

1. 域名DNS解析

2. TCP連接: TCP三次握手

3. 發送請求

4. 接受響應

5. 渲染頁面

13、dns解析原理

 第一步:客戶機提出域名解析請求,並將該請求發送給本地的域名服務器.
  第二步:當本地的域名服務器收到請求后,就先查詢本地的緩存,如果有該紀錄項,則本地的域名服務器就直接把查詢的結果返回.
  第三步:如果本地的緩存中沒有該紀錄,則本地域名服務器就直接把請求發給根域名服務器,然后根域名服務器再返回給本地域名服務器一個所查詢域(根的子域)的主域名服務器的地址.
  第四步:本地服務器再向上一步返回的域名服務器發送請求,然后接受請求的服務器查詢自己的緩存,如果沒有該紀錄,則返回相關的下級的域名服務器的地址.
  第五步:重復第四步,直到找到正確的紀錄.
  第六步:本地域名服務器把返回的結果保存到緩存,以備下一次使用,同時還將結果返回給客戶機.

主機向本地域名服務器的查詢一般都是采用遞歸查詢,本地域名服務器向根域名服務器的查詢的迭代查詢。

其他

哈希表解決沖突辦法 

哈希表查找元素的過程

哈希表某個數據從桶中刪除怎么辦

前序中序還原二叉樹

https://blog.csdn.net/w823626691/article/details/23101303

兩千萬文件找最小的一千個(大頂堆)

https://blog.csdn.net/Nick_666/article/details/78281008

 

一句話總結:內存無法裝下,用比較速度最快的數據結構。

先找最大的1000個整數

1、內存無法裝下:先取出1001個整數,構建一個最小堆,堆頂永遠是最小的整數。

2、比較:從剩余的整數中一次取出一個,跟最小堆堆頂相比,如果比堆頂小,就pass掉,接着取;如果比最小堆堆頂大,那么將之替換掉堆頂,然后調整最小堆

3、結果:100億個整數全部操作完后,拋開堆頂,剩下的1000個就是最大的1000個整數。

KMP算法:

1. 對模式串預處理,生成next數組

2. 進入主循環,遍歷主串

2.1. 比較主串和模式串的字符

2.2. 如果發現壞字符,查詢next數組,得到匹配前綴所對應的最長可匹配前綴子串,移動模式串到對應位置

2.3.如果當前字符匹配,繼續循環

next數組用於記錄模式串每一位的最長公共前后綴,也就是標記實際匹配過程中在某一位遇到不匹配的情況時,模式串的 j 應該移動到的位置

1. next生成過程就是模式串自己匹配自己的過程,首先固定一個模式串,然后拿另一個模式串從頭開始不斷的和第一個模式串對,字符一樣就說明當前位置開始往后的字符和字符串開頭往后的字符匹配,就是有公共前后綴,並得到長度。

2. 首先模式串的第0位字符公共前后綴長度為0,實際匹配過程中要匹配的串和模式串的第0位都不匹配的話,說明這個位置沒得跳轉,所以ne[0]=0;

3. 進入循環,首先 i 在1的位置,k在0的位置(要注意k的位置和next數下標沒關系,k是對於原來模式串而言的位置,現在在第0個a上),如圖中第1次匹配所示,發現p[i]=p[k],說明 i 位置最長公共前后綴為1,記入next數組,ne[1]=1。現在k=1,在第二個a上。緊接着i=2,發現p[i]!=p[k],這時候怎么辦呢?問問k前面的老兄:“你的公共前后綴是多少啊?”,k-1說自己公共前后綴是0。那好吧,沒得跳轉了,直接ne[2]=0,下一個字符只能從頭開始對了。

4. 進入第2次匹配。此時i=3,k=0,發現一路順風順水,i=3后面的字符和從頭開始的字符串一直都匹配,所以公共前后綴長度不斷加1,直到i=8。此時k=5,而p[i]!=p[k]。這時候再問問k前面的老兄的公共前后綴,k-1說我的公共前后綴是2。那么說明從k開始往前的兩個字符和從頭開始的兩個字符是一樣的。那么我們下一次直接從第三個字符匹配。

5. 進入第3次匹配。此時k=2,i=8。發現還有p[i]!=p[k],再問問k-1,k-1說我的公共前后綴長度為1,說明k之前的那1個字符和開頭的第1個字符是一樣的,那么我們下一次直接從第2個字符匹配。

6. 進入第4次匹配。此時k=1,  i=8。發現終於p[i]=p[k],那么ne[i]等於多少呢,就是之前k-1的即此時k的公共前后綴的數目加上這次匹配的數目,即ne[8]=2;匹配完成。

實際匹配過程和生成next數組的過程類似。用模式串不斷對比要匹配的串,然后進行根據next數組進行跳轉。

時間復雜度O(m+n)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM