一、 PHP部分
1、PHP如何實現靜態化
PHP的靜態化分為:純靜態和偽靜態。其中純靜態又分為:局部純靜態和全部純靜態。
PHP偽靜態:利用Apache mod_rewrite實現URL重寫的方法;
PHP純靜態,就是生成HTML文件的方式,我們須要開啟PHP自帶的緩存機制,即ob_start來開啟緩存。
2、PHP經典四大排序算法
PHP的四種基本排序算法為:冒泡排序、插入排序、選擇排序和快速排序。
冒泡排序:對數組進行多輪冒泡,每一輪對數組中的元素兩兩比較,調整位置,冒出一個最大的數來。
插入排序:假設組前面的元素是排好序的,遍歷數組后面的元素,在已排好序的元素隊列中找到合適的位置,插入其中。
選擇排序:進行多次選擇,每次選出最大元素放入指定位置。
快速排序:遞歸算法。先選擇數組的第一個元素作為標準,然后把小于或等于它和大于它的數分別放入兩個數組中,對這兩個數組也進行相同的處理,最后合并這兩個數組和第一個元素。
3、PHP常見運行模式
1)CGI(通用網關接口/ Common Gateway Interface)
2)FastCGI(常駐型CGI / Long-Live CGI)lamp
3)CLI(命令行運行 / Command Line Interface)
4)Web模塊模式(Apache等Web服務器運行的模式)
5)ISAPI(Internet Server Application Program Interface)
4、你了解設計模式嗎?說下你最常用的設計模式
大概有23種設計模式,PHP常見的大概有10幾種,雖然不算是基礎,但是你必須要懂得。
總體來說設計模式分為三大類:
1、創建型模式共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
2、結構型模式共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
3、行為型模式共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。
觀察者模式是如何實現的?工廠模式是如何實現的?適配器模式是如何實現的?……
觀察者模式:定義了對象之間的一對多依賴,這樣一來,當一個對象改變狀態時,它的所有依賴者都會收到通知并且有所作為。即出版者+訂閱者=觀察者模式。
工廠模式 :將調用者和創建者分離,調用者直接向工廠類請求獲取調用對象,減少代碼耦合,提高系統的維護性和擴展性;
工廠模式應用場景:有多個產品類時就要用到工廠模式,比如在數據庫連接中,我們可以采用多種數據庫連接方法,有mysql擴展,mysqli擴展,PDO擴展等,在這種情況下我們可以一個擴展對應一個產品類,然后采用工廠模式。
適配器模式核心思想:把對某些相似的類的操作轉化為一個統一的“接口”(這里是比喻的說話)–適配器,或者比喻為一個“界面”,統一或屏蔽了那些類的細節。適配器模式還構造了一種“機制”,使“適配”的類可以很容易的增減,而不用修改與適配器交互的代碼,符合“減少代碼間耦合”的設計原則。
5、PHP的優化方案
1.如果一個方法可靜態化,就對它做靜態聲明。速率可提升至4倍。
2.echo 比 print 快。
3.使用echo的多重參數(譯注:指用逗號而不是句點)代替字符串連接。
4.在執行for循環之前確定最大循環數,不要每循環一次都計算最大值。
5.注銷那些不用的變量尤其是大數組,以便釋放內存。
6.盡量避免使用__get,__set,__autoload。
7.require_once()代價昂貴。
8.在包含文件時使用完整路徑,解析操作系統路徑所需的時間會更少。
9.如果你想知道腳本開始執行(譯注:即服務器端收到客戶端請求)的時刻,使用$_SERVER[‘REQUEST_TIME’]要好于time()。
10.函數代替正則表達式完成相同功能。
11.str_replace函數比preg_replace函數快,但strtr函數的效率是str_replace函數的四倍。
12.如果一個字符串替換函數,可接受數組或字符作為參數,并且參數長度不太長,那么可以考慮額外寫一段替換代碼,使得每次傳遞參數是一個字符,而不是只寫一行代碼接受數組作為查詢和替換的參數。
13.使用選擇分支語句(譯注:即switch case)好于使用多個if,else if語句。
14.用@屏蔽錯誤消息的做法非常低效。
15.打開apache的mod_deflate模塊。
16.數據庫連接當使用完畢時應關掉。
17.row[‘id’]的效率是row[‘id’]的效率是row[‘id’]的效率是row[id]的7倍。
18.錯誤消息代價昂貴。
19.盡量不要在for循環中使用函數,比如for ($x=0; x<count(x < count(x<count(array); $x)每循環一次都會調用count()函數。
20.在方法中遞增局部變量,速度是最快的。幾乎與在函數中調用局部變量的速度相當。
21.遞增一個全局變量要比遞增一個局部變量慢2倍。
22.遞增一個對象屬性(如:$this->prop++)要比遞增一個局部變量慢3倍。
23.遞增一個未預定義的局部變量要比遞增一個預定義的局部變量慢9至10倍。
24.僅定義一個局部變量而沒在函數中調用它,同樣會減慢速度(其程度相當于遞增一個局部變量)。PHP大概會檢查看是否存在全局變量。
25.方法調用看來與類中定義的方法的數量無關,因為我(在測試方法之前和之后都)添加了10個方法,但性能上沒有變化。
26.派生類中的方法運行起來要快于在基類中定義的同樣的方法。
27.調用帶有一個參數的空函數,其花費的時間相當于執行7至8次的局部變量遞增操作。類似的方法調用所花費的時間接近于15次的局部變量遞增操作。
28.用單引號代替雙引號來包含字符串,這樣做會更快一些。因為PHP會在雙引號包圍的字符串中搜尋變量,單引號則不會
6、說下你了解的session和cookie
1、存儲位置不同
cookie的數據信息存放在客戶端瀏覽器上。
session的數據信息存放在服務器上。
2、存儲容量不同
單個cookie保存的數據<=4KB,一個站點最多保存20個Cookie。
對于session來說并沒有上限,但出于對服務器端的性能考慮,session內不要存放過多的東西,并且設置session刪除機制。
3、存儲方式不同
cookie中只能保管ASCII字符串,并需要通過編碼方式存儲為Unicode字符或者二進制數據。
session中能夠存儲任何類型的數據,包括且不限于string,integer,list,map等。
4、隱私策略不同
cookie對客戶端是可見的,別有用心的人可以分析存放在本地的cookie并進行cookie欺騙,所以它是不安全的。
session存儲在服務器上,對客戶端是透明對,不存在敏感信息泄漏的風險。
5、有效期上不同
開發可以通過設置cookie的屬性,達到使cookie長期有效的效果。
session依賴于名為JSESSIONID的cookie,而cookie JSESSIONID的過期時間默認為-1,只需關閉窗口該session就會失效,因而session不能達到長期有效的效果。
6、服務器壓力不同
cookie保管在客戶端,不占用服務器資源。對于并發用戶十分多的網站,cookie是很好的選擇。
session是保管在服務器端的,每個用戶都會產生一個session。假如并發訪問的用戶十分多,會產生十分多的session,耗費大量的內存。
7、瀏覽器支持不同
假如客戶端瀏覽器不支持cookie:
cookie是需要客戶端瀏覽器支持的,假如客戶端禁用了cookie,或者不支持cookie,則會話跟蹤會失效。關于WAP上的應用,常規的cookie就派不上用場了。
運用session需要使用URL地址重寫的方式,就是把session id附加在URL路徑的后面,附加的方式也有兩種,一種是作為URL路徑的附加信息,另一種是作為查詢字符串附加在URL后面。。一切用到session程序的URL都要進行URL地址重寫,否則session會話跟蹤還會失效。
假如客戶端支持cookie:
cookie既能夠設為本瀏覽器窗口以及子窗口內有效,也能夠設為一切窗口內有效。
session只能在本窗口以及子窗口內有效。
8、跨域支持上不同
cookie支持跨域名訪問。
session不支持跨域名訪問。
7、如何實現不基于session和cookie的用戶認證。
將用戶信息加密放到http的header部分,每次拿到http的時候,驗證獲取header的信息。
8、什么是CSRF攻擊,XSS攻擊?如何防范
CSRF(Cross-site request forgery)跨站請求偽造,黑客建立一個偽造網站或發送郵箱帶了一個正常URL鏈接來讓正常用戶訪問,來讓正常用戶讓自己瀏覽器里的COOKIE權限來執行一些非法請求,
如轉賬,提權等操作,
防范方法有,驗證 HTTP Referer 字段;在請求地址中添加 token 并驗證;
XSS攻擊
主要將XSS代碼提交存儲在服務器端(數據庫,內存,文件系統等),下次請求目標頁面時不用再提交XSS代碼。當目標用戶訪問該頁面獲取數據時,XSS代碼會從服務器解析之后加載出來,返回到瀏覽器做正常的HTML和JS解析執行,XSS攻擊就發生了。
防范方法:通過過濾是針對非法的HTML代碼包括單雙引號等,使用htmlspecialchars()函數
9、你了解RESTful API嗎?說說干什么用的。
RESTful API是REST風格的API,是一套用來規范多種形式的前端和同一個后臺的交互方式的協議。RESTful API由后臺也就是SERVER來提供前端來調用;前端調用API向后臺發起HTTP請求,后臺響應請求將處理結果反饋給前端。
10、php設計模式六大原則
單一職責原則:不要存在多于一個導致類變更的原因。通俗的說,即一個類只負責一項職責。
開放封閉原則:一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。
里氏替換原則:所有引用基類的地方必須能透明地使用其子類的對象。
接口隔離原則:客戶端不應該依賴它不需要的接口;一個類對另一個類的依賴應該建立在最小的接口上。
迪米特原則:一個對象應該對其他對象保持最少的了解。
依賴倒置原則:高層模塊不應該依賴低層模塊,二者都應該依賴其抽象;抽象不應該依賴細節;細節應該依賴抽象。
11、如何實現自動加載?不用composer如何實現?PSR-4是什么?
自動加載就是當我們在當前文件中實例化一個不存在的類時,調用自動加載機制引入相應的類文件。
注:自動加載有兩種方式(都是php內置的),一種是通過__autoload(),另一種是通過spl_autoload_register()。
PSR是PHP Standards Recommendation的簡稱,制定的代碼規范,簡稱PSR,是代碼開發的事實標準。
PSR-4使代碼更加規范,能夠滿足面向package的自動加載,它規范了如何從文件路徑自動加載類,同時規范了自動加載文件的位置。
12、抽象類和接口分別是什么,他們區別?
抽象類:是基于類來說,其本身就是類,只是一種特殊的類,不能直接實例,可以在類里定義方法,屬性。類似于模版,規范后讓子類實現詳細功能。
接口(Interface)—— 定義行為
抽象類(Abstract Class) —— 實現行為
具體類(class)——執行行為
接口:主要基于方法的規范,有點像抽象類里的抽象方法,只是其相對于抽象方法來說,更加獨立。可讓某個類通過組合多個方法來形成新的類。
抽象類與接口的相同點:
1、都是用于聲明某一種事物,規范名稱、參數,形成模塊,未有詳細的實現細節。
2、都是通過類來實現相關的細節工作
3、語法上,抽象類的抽象方法與接口一樣,不能有方法體,即{}符號
4、都可以用繼承,接口可以繼承接口形成新的接口,抽象類可以繼承抽象類從而形成新的抽象類
抽象類與接口的不同點:
1、抽象類可以有屬性、普通方法、抽象方法,但接口不能有屬性、普通方法、可以有常量
2、抽象類內未必有抽象方法,但接口內一定會有“抽象”方法
3、語法上有不同
4、抽象類用abstract關鍵字在類前聲明,且有class聲明為類,接口是用interface來聲明,但不能用class來聲明,因為接口不是類。
5、抽象類的抽象方法一定要用abstract來聲明,而接口則不需要
6、抽象類是用extends關鍵字讓子類繼承父類后,在子類實現詳細的抽象方法。而接口則是用implements讓普通類在類里實現接口的詳細方法,且接口可以一次性實現多個方法,用逗號分開各個接口就可
13、微服務的了解
概念:又稱微服務架構,是一種架構風格,它將應用程序構建為以業務領域為模型的小型自治服務集合 。
優勢:
獨立開發 – 所有微服務都可以根據各自的功能輕松開發
獨立部署 – 基于其服務,可以在任何應用程序中單獨部署它們
故障隔離 – 即使應用程序的一項服務不起作用,系統仍可繼續運行
混合技術堆棧 – 可以使用不同的語言和技術來構建同一應用程序的不同服務
粒度縮放 – 單個組件可根據需要進行縮放,無需將所有組件縮放在一起
特點:
解耦 – 系統內的服務很大程度上是分離的。因此,整個應用程序可以輕松構建,更改和擴展
組件化 – 微服務被視為可以輕松更換和升級的獨立組件
業務能力 – 微服務非常簡單,專注于單一功能
自治 – 開發人員和團隊可以彼此獨立工作,從而提高速度
持續交付 – 通過軟件創建,測試和批準的系統自動化,允許頻繁發布軟件
責任 – 微服務不關注應用程序作為項目。相反,他們將應用程序視為他們負責的產品
分散治理 – 重點是使用正確的工具來做正確的工作。這意味著沒有標準化模式或任何技術模式。開發人員可以自由選擇最有用的工具來解決他們的問題
敏捷 – 微服務支持敏捷開發。任何新功能都可以快速開發并再次丟棄
14、垃圾回收機制
php7的垃圾回收包含兩個部分,一個是垃圾收集器,一個是垃圾回收算法。
垃圾收集器,把剛剛提到的,可能是垃圾的元素收集到回收池中 也就是把變量的 zend_refcount>0的變量 放在回收池中。 當回收池的值達到一定額度了,會進行統一遍歷處理。進行模擬刪除,如果zend_refcount=0那就認為是垃圾,直接刪除它。 遍歷回收池中的每一個變量,根據每一個變量,再遍歷每一個成員,如果成員還有嵌套的話繼續遍歷。然后把所有成員的 做模擬的 refcount -1。如果此時外部的變量的 引用次數為 0 。那么可以視為垃圾,清楚。如果大于0,那么恢復引用次數,并從垃圾回收池中取出。
15、高并發解決方案
1、流量優化
防盜鏈處理(去除惡意請求)
2、前端優化
(1) 減少HTTP請求[將css,js等合并]
(2) 添加異步請求(先不將所有數據都展示給用戶,用戶觸發某個事件,才會異步請求數據)
(3) 啟用瀏覽器緩存和文件壓縮
(4) CDN加速
(5) 建立獨立的圖片服務器(減少I/O)
3、服務端優化
(1) 頁面靜態化
(2) 并發處理
(3) 隊列處理
4、數據庫優化
(1) 數據庫緩存
(2) 分庫分表,分區
(3) 讀寫分離
(4) 負載均衡
5、web服務器優化
(1) nginx反向代理實現負載均衡
(2) lvs實現負載均衡
16、防止sql注入
防止注入的第一步就是驗證數據,可以根據相應類型進行嚴格的驗證。比如 int 類型直接同過 intval 進行轉換就行:
參數化綁定,防止 SQL 注入的又一道屏障。php MySQLi 和 PDO 均提供這樣的功能。比如 MySQLi 可以這樣去查詢:
17、魔術常量、超全局變量、魔術方法
https://blog.csdn.net/t707584896/article/details/128798962
18、對象的克隆與引用有什么區別
引用就是:當改變Object1對象時,Object1對象時,Object1對象時,Object2也做相同的變化。
克隆就是:克隆的對象$Object1與原來的對象沒有任何關系,它是將原來的對象從當前位置從新復制了一份。
19、什么是composer?composer的意義?工作原理
composer是一個依賴管理工具,composer會幫你安裝這些依賴的庫文件;
比如composer可以解決自動加載類,不用你寫過多的new。
二. 數據庫方面
20、數據庫三大范式是什么?
第一范式:
1NF是對屬性的原子性,要求屬性具有原子性,不可再分解;
第二范式:
2NF是對記錄的唯一性,要求記錄有唯一標識,即實體的唯一性,即不存在部分依賴;
第三范式:
3NF是對字段的冗余性,要求任何字段不能由其他字段派生出來,它要求字段沒有冗余,即不存
21、msyql的存儲引擎,以及各自的區別,myisam和innodb區別
InnoDB是MySQL默認的存儲引擎。
2.只有 InnoDB 支持事務,MyISAM不支持事務。
3.MyISAM不支持行級鎖和外鍵, InnoDB支持。
4.InnoDB表的大小更加的大,用MyISAM可省很多的硬盤空間。
5.InnoDB 引擎的索引和文件是存放在一起的,找到索引就可以找到數據,是聚簇式設計。
6.MyISAM 引擎采用的是非聚簇式(即使是主鍵)設計,索引文件和數據文件不在同一個文件中。
22、mysql索引有哪些,你是如何做索引的?
從數據結構角度
(1)、B+樹索引(O(log(n))):關于B+樹索引,可以參考 MySQL索引背后的數據結構及算法原理
(2)、hash索引:
從物理存儲角度
(1)、聚集索引(clustered index)
(2)、非聚集索引(non-clustered index)
從邏輯角度
(1)、主鍵索引:主鍵索引是一種特殊的唯一索引,不允許有空值
(2)、普通索引或者單列索引
(3)、多列索引(復合索引):復合索引指多個字段上創建的索引,只有在查詢條件中使用了創建索引時的第一個字段,索引才會被使用。使用復合索引時遵循最左前綴集合
(4)、唯一索引或者非唯一索引
(5)、空間索引:空間索引是對空間數據類型的字段建立的索引
23、mysql索引優化
列越小越快
枚舉類型替代varchar
避免null值
固定長度的表比動態的快(避免text等不定長字段)
垂直分表(降低表的復雜度,不常用的字段分離出來單獨存儲)
合理設置索引
分表,分布式(主從)
24、mysql的事務特性
原子性:事務是一個不可分割的工作單位,要么同時成功,要么同時失敗。例:當兩個人發起轉賬業務時,如果A轉賬發起,而B因為一些原因不能成功接受,事務最終將不會提交,則A和B的請求最終不會成功。
持久性:一旦事務提交,他對數據庫的改變就是永久的。注:只要提交了事務,將會對數據庫的數據進行永久性刷新。
隔離性:多個事務之間相互隔離的,互不干擾
一致性:事務執行接收之后,數據庫完整性不被破壞
注意:只有當前三條性質都滿足了,才能保證事務的一致性
25、mysql的讀寫分離
讀寫分離解決的是,數據庫的寫操作,影響了查詢的效率,適用于讀遠大于寫的場景。讀寫分離的實現基礎是主從復制,主數據庫利用主從復制將自身數據的改變同步到從數據庫集群中,然后主數據庫負責處理寫操作(當然也可以執行讀操作),從數據庫負責處理讀操作,不能執行寫操作。并可以根據壓力情況,部署多個從數據庫提高讀操作的速度,減少主數據庫的壓力,提高系統總體的性能。
26、msyql如何分表分庫分表
https://blog.csdn.net/shida219/article/details/117981566
27、msyql悲觀和樂觀鎖
https://blog.csdn.net/weixin_45433031/article/details/120838045
28、什么是msyql索引回表和索引覆蓋
InnoDB引擎中,非主鍵索引查找數據時需要先找到主鍵,再根據主鍵查找具體行數據,這種現象叫回表查詢
將查詢sql中的字段添加到聯合索引里面,只要保證查詢語句里面的字段都在索引文件中,就無需進行回表查詢;
29、msyql索引失效
1、like查詢以“%”開頭;
2、or語句前后沒有同時使用索引;
3、組合索引中不是使用第一列索引;
4、在索引列上使用“IS NULL”或“IS NOT NULL”操作;
5、在索引字段上使用“not”,“<>”,“!=”。
6、如果列類型是字符串,那一定要在條件中將數據使用引號引用起來,否則不使用索引
7、當全表掃描速度比索引速度快時,mysql會使用全表掃描,此時索引失效。
30、什么是死鎖?什么是臟讀?幻讀?不可重復讀?
臟讀(無效的數據)
a事務把數據改完之后并沒有提交,b事務讀到這個改完數據之后的事務,
b事務讀完之后,a事務又把數據做了一個回滾操作,這種現象叫臟讀
不可重復讀
a事務把數據讀完拿去用了,b事務剛好直接把數據給改了,并且提交了,
a事務會發現之前讀的數據不準確了
幻讀現象
是不可重復讀的一種特殊現象,
舉例:假設一張表一共有10條數據,a事務把id大于3的數據name全部改成了xx,
就在剛剛改完的那一刻,b事務又插入一條數據,a事務改完之后,會發現有一條數據沒有修改成功
31、MySQL數據庫cpu飆升到100%的話怎么處理?
https://blog.csdn.net/t707584896/article/details/129971047
32、MySQL主從復制解決了哪些問題?
1、數據的備份(很多企業用從庫來做專業數據庫備份服務器)
2、讀寫分離,這樣減少主庫的壓力,支持更大的并發,主寫從讀。還可以單獨使用一個從庫來做為企業內部人員查詢數據使用的服務器,這樣更有利于減少線上服務器的訪問壓力。
3、高可用,主從復制+故障切換,實現線上業務不宕機運行。
33、binlog和redo log有什么區別?
1.Redo Log是屬于InnoDB引擎功能,Binlog是屬于MySQL Server自帶功能,并且是以二進制文件記錄。
2.Redo Log屬于物理日志,記錄該數據頁更新狀態內容,Binlog是邏輯日志,記錄更新過程。
3.Redo Log日志是循環寫,日志空間大小是固定,Binlog是追加寫入,寫完一個寫下一個,不會覆蓋使用。
4.Redo Log作為服務器異常宕機后事務數據自動恢復使用,Binlog可以作為主從復制和數據恢復使用。Binlog沒有自動crash-safe能力。
5.由binlog和redo log的概念和區別可知:binlog日志只用于歸檔,只依靠binlog是沒有crash-safe能力的。但只有redo log也不行,因為redo log是InnoDB特有的,且日志上的記錄落盤后會被覆蓋掉。因此需要binlog和redo log二者同時記錄,才能保證當數據庫發生宕機重啟時,數據不會丟失
34、慢SQL如何定位呢?
1.首先確認是否開啟了慢查詢
2.設置慢查詢的時間限制
3.查詢慢查詢日志可定位具體的慢sql
4.相關sql查詢
5.用Explain分析具體的sql語句
id:選擇標識符
select_type:表示查詢的類型。
table:輸出結果集的表
partitions:匹配的分區
type:表示表的連接類型
possible_keys:表示查詢時,可能使?的索引
key:表示實際使?的索引
key_len:索引字段的長度
ref:列與索引的比較
rows:掃描出的行數(估算的行數)
filtered:按表條件過濾的?百分比
Extra:執行情況的描述和說明
35、MySQL單表過億條數據,如何優化查詢速度?
分庫:是為了解決數據庫連接資源不足問題,和磁盤IO的性能瓶頸問題。
分表:是為了解決單表數據量太大,sql語句查詢數據時,即使走了索引也非常耗時問題。此外還可以解決消耗cpu資源問題。
分庫分表:可以解決 數據庫連接資源不足、磁盤IO的性能瓶頸、檢索數據耗時 和 消耗cpu資源等問題。
https://www.zhihu.com/question/439988021/answer/2436380280
36、百億級數據分表后怎么分頁查詢?
分表規則定位具體表,或者雙寫
最后考慮 離線數倉或者ES查詢
37、redis和memcache有什么區別
多線程:memcache支持多線程,Redis支持單線程
持久化:Redis支持持久化(周期性的將數據寫到磁盤中),memcache不支持持久化
分布式:Redis做主從結構,memcache服務器需要通過hash一致化來支撐主從結構
38、redis常見數據結構有哪些
最常用的的有5種,字符串(String)、哈希(Hash)、列表(list)、集合(set)、有序集合(ZSET)
39、redis緩存雪崩、緩存穿透、緩存擊穿
https://blog.csdn.net/t707584896/article/details/128812799
40、redis淘汰策略
volatile-lru,針對設置了過期時間的key,使用lru算法進行淘汰。
allkeys-lru,針對所有key使用lru算法進行淘汰。
volatile-lfu,針對設置了過期時間的key,使用lfu算法進行淘汰。
allkeys-lfu,針對所有key使用lfu算法進行淘汰。
volatile-random,從所有設置了過期時間的key中使用隨機淘汰的方式進行淘汰。
allkeys-random,針對所有的key使用隨機淘汰機制進行淘汰。
volatile-ttl,刪除生存時間最近的一個鍵。
noeviction(默認),不刪除鍵,值返回錯誤。
41、redis分布式鎖怎么實現
https://www.zhihu.com/question/300767410/answer/1931519430
42、Redis的持久化機制
區別:
RDB持久化是指在指定的時間間隔內將內存中的數據集快照寫入磁盤,實際操作過程就是有一個fork子進程,先將數據集寫入到臨時文件中,寫入成功后,再替換之前的文件,用二進制壓縮存儲。
AOF持久化以日志的形式記錄服務器所處理的每一個寫、刪除操作,查詢操作不會記錄,以文本的方式記錄,可以打開文件看到詳細的操作記錄。
RDB的優缺點:
優點:RDB持久化文件,速度比較快,而且存儲的是一個二進制文件,傳輸起來很方便。
缺點:RDB無法保證數據的絕對安全,有時候就是1s也會有很大的數據丟失。
AOF的優缺點:
優點:AOF相對RDB更加安全,一般不會有數據的丟失或者很少,官方推薦同時開啟AOF和RDB。
缺點:AOF持久化的速度,相對于RDB較慢,存儲的是一個文本文件,到了后期文件會比較大,傳輸困難。
43、redis如何解決秒殺超賣問題
隊列、事物、分布式鎖等很多方式,自行了解
https://zhuanlan.zhihu.com/p/268290754
44、MySQL里有2000w數據,redis中只存20w數據,如何保證redis中數據都是熱點數據
分析題目:保證Redis 中的 20w 數據都是熱點數據 說明是被頻繁訪問的數據,并且要保證Redis的內存能夠存放20w數據,要計算出Redis內存的大小。
a、保留熱點數據:對于保留 Redis 熱點數據來說,我們可以使用 Redis 的內存淘汰策略來實現,可以使用allkeys-lru淘汰策略,該淘汰策略是從 Redis 的數據中挑選最近最少使用的數據刪除,這樣頻繁被訪問的數據就可以保留下來了。
b、保證 Redis 只存20w的數據:1個中文占2個字節,假如1條數據有100個中文,則1條數據占200字節,20w數據 乘以 200字節 等于 4000 字節(大概等于38M);所以要保證能存20w數據,Redis 需要38M的內存。
45、redis主從哨兵和集群的區別
一、架構不同
redis主從:一主多從;
redis集群:多主多從;
二、存儲不同
redis主從:主節點和從節點都是存儲所有數據;
redis集群:數據的存儲是通過hash計算16384的槽位,算出要將數據存儲的節點,然后進行存儲;
三、選舉不同
redis主從:通過啟動redis自帶的哨兵(sentinel)集群進行選舉,也可以是一個哨兵
選舉流程:1、先發現主節點fail的哨兵,將成為哨兵中的leader,之后的主節點選舉將通過這個leader進行故障轉移操作,從存活的slave中選舉新的master,新的master選舉同集群的master節點選舉類似;
redis集群:集群可以自己進行選舉
選舉流程:1、當主節點掛掉,從節點就會廣播該主節點fail;
2、延遲時間后進行選舉(延遲的時間算法為:延遲時間+隨機數+rank*1000,從節點數據越多,rank越小,因為主從數據復制是異步進行的,所以 所有的從節點的數據可能會不同),延遲的原因是等待主節點fail廣播到所有存活的主節點,否則主節點會拒絕參加選舉;
3、參加選舉的從節點向所有的存活的節點發送ack請求,但只有主節點會回復它,并且主節點只會回復第一個到達參加選舉的從節點,一半以上的主節點回復,該節點就會成為主節點,廣播告訴其他節點該節點成為主節點。
四、節點擴容不同
redis主從:只能擴容從節點,無法對主節點進行擴容;
redis集群:可以擴容整個主從節點,但是擴容后需要進行槽位的分片,否則無法進行數據寫入,命令為:
/usr/local/redis-5.0.3/src/redis-cli -a zhuge --cluster reshard 192.168.0.61:8001,其中的192.168.0.61:8001為新加入的主從節點;
46、redis消息隊列如何防止數據丟失?
Redis實現消息隊列有兩種形式:
廣播訂閱模式:基于Redis的 Pub/Sub 機制,一旦有客戶端往某個key里面 publish一個消息,所有subscribe的客戶端都會觸發事件
集群訂閱模式:基于Redis List雙向+ 原子性 + BRPOP
Redis消息隊列時,當Redis宕機后,消息可能會丟失(也要看持久化的策略)。如果收消息方(消費端)未有重發和驗證機制,Redis內的數據會出現丟失。所以,使用Redis的作為消息隊列,通常是對于消息的準確性并非特別高的場景。
如果絕對的保證數據最終一致性,保證消息百分百不丟,那么需要:
1.寫入時候要求啟用事務處理,保證寫一定成功。
-
redis配置成任何變更一定實時持久化,比如存儲端是磁盤的話,每次變更馬上同步寫入磁盤,才算完成。redis是支持這種方式配置的,但是這么做會使它的內存數據庫特性完全消失,性能變得十分低下。
-
消費端也要實現事務方式,處理完成后,再回來真實刪除消息。
-
多線程或者多端同時并發處理,可以通過鎖的方式來規避。
3 4的需求需要自己實現,可以一起考慮,用另外一個隊列實現的方式也可以,但是更好的方式是在隊列內部實現個計數器。hash格式的加個字段加數值,list的先推一個數值打底,string的頭上加個數值再加個分隔符,就可以做個簡單計數器了,雖然土,勝在夠實用。
除了特定的系統之外,一般不會要求這么強的一致性,實現倒不難,但是性能會很差很差。
銀行類支付類業務會要求嚴格的事務一致性,而互聯網類業務一般會用點取巧的方式,就是可以容忍極短時間內少量數據丟失的方式,換取更高性能。
比如上面的redis處理,可以改為1000條數據變更的時候再真實落盤,即寫入磁盤。那么極限情況下,如突然斷電,存在可能丟失這1000條數據的風險。當然這種情況出現的概率也是很低的(遠離藍翔挖掘機?),所以大部分場景下可以接受。
47、MQ消息隊列你怎么選擇,各大優劣?
1 RabbitMQ
優點:輕量級、容易部署和使用、支持多種客戶端開發語言、支持靈活的路由配置
缺點:對消息堆積的支持并不好、性能和吞吐量較差、使用 Erlang 語言編寫,比較難進行二次開發
2 RocketMQ
優點:性能好、穩定可靠、有活躍的中文社區、使用 Java 開發,容易進行二次開發、特點響應快
缺點:兼容性較差
3 Kafka
優點:兼容性極好、設計上大量使用了批量和異步的思想,有超高的性能、
缺點:由于 “先攢一波再一起處理” 的設計,時延較高,不太適合在線業務場景
4 總結
如果說,消息隊列并不是你將要構建的主角之一,對消息隊列的功能和性能都沒有很高的要求,只需要一個開箱即用易于維護的產品,建議使用 RabbitMQ。
如果系統使用消息隊列的主要場景是處理在線業務,比如在交易系統中用消息隊列傳遞訂單,那 RocketMQ 的低延遲和金融級的穩定性是我們需要的。
如果需要的是處理海量的數據,像收集日志、監控信息或是前端的埋點這類數據,或是應用場景大量使用了大數據、流計算相關的開源產品,那 Kafka 是最適合的消息隊列。
48、int(1)和int(10)區別
INT(1) 和 INT(10)本身沒有區別,但是INT[(M)] 加上ZEROFILL值后,會對值有寬度的設置,不夠位數前面自動補0.
49、MySQL:數據庫自增 ID 用完了會咋樣?
把主鍵類型改為 bigint,也就是 8 個字節。這樣能存儲的最大數據量就是 2^64
PS:單表 21 億的數據量顯然不現實,一般來說數據量達到 500 萬就該分表了
三、 服務器&其它方面
50、說下一些你常用的linux命令
1.pwd 命令 2.ls 命令 3.cd 命令 4.man 命令 5.grep 命令 6.find 命令 7.chmod 命令 8.ps 命令 9.kill 命令 10.tail 命令 11.netstat 命令 8.date 查看當前系統時間 10.echo 打印
51、多進程同時讀寫一個文件
pid=pcntlfork();pid = pcntl_fork();pid=pcntlf?ork();fp = fopen(“test.txt”, “a”);if (flock(KaTeX parse error: Expected '}', got 'EOF' at end of input: …K_EX)){ fwrite(fp, “content”); fflush(fp);flock(fp); flock(fp);flock(fp, LOCK_UN);}else{ echo “此文件正在被其他進程占用”;}
52、常用的服務端口號
https://blog.csdn.net/zhanghongshun624/article/details/127920039
53、api接口的安全性設計
https://blog.csdn.net/t707584896/article/details/129266951
54、如何防止數據重復提交,重復寫入
主要從并發上面考慮:緩存、分流、redis鎖、隊列、mysql所有等方面
55、SSO單點登陸
在多個系統中,只需要登陸/注銷一次,就可以完成所有系統中的用戶登陸驗證。
同一個域名下的子域名各個系統可以使用設置頂級域名的cookie存儲登陸信息來實現;
攔截登陸請求給用戶中心發放令牌到子系統,子系統校驗令牌后局部登陸,注銷時用戶中心發送請求到各個子系統注銷局部登陸;
jwt,各個子系統使用相同的secret,相同的token可以在不同系統中使用;
以上方式的前提都要有統一的用戶信息存儲中心。
56、兩臺 mysql 服務器,其中一臺掛了,怎么讓業務端無感切換
https://blog.csdn.net/sinat_36757755/article/details/124049382
57、微服務之間怎么通信
1、基于網關 API
2、基于 RPC
3、基于 SideCar
https://zhuanlan.zhihu.com/p/452558073
58、TCP三次握手四次揮手
握手:
客戶端請求服務端,發送連接請求標示和一串順序碼(X)
服務端收到請求,回復確認標示和順序碼(X)+1的確認碼和另一個順序碼(Y)
客戶端驗證(X)+1確認碼,通過后發送確認標示和(Y)+1的順序碼給服務端,服務端驗證通過后建立連接
揮手:
第一次握手:TCP發送一個FIN(結束),用來關閉客戶到服務端的連接。
第二次握手:服務端收到這個FIN,他發回一個ACK(確認),確認收到序號為收到序號+1。
第三次握手:服務端發送一個FIN(結束)到客戶端,服務端關閉客戶端的連接。
第四次握手:客戶端發送ACK(確認)報文確認,并將確認的序號+1,這樣關閉完成
為什么是四次不是三次?
server端收到結束請求后,需要等待數據傳輸完畢,所以只能先發送一個收到請求的確認信息給客戶端,等數據傳輸完畢后再發送結束報文。
59、正常請求一個php網站,在瀏覽器輸入網址打開網站,顯示網頁。但是在整個請求流程中瀏覽器做什么?服務器又是怎么在后臺執行的?接下來就簡單解析下一個完整的PHP請求的執行過程。
1、構建請求
2、查找緩存
3、域名解析
4、與服務器建立連接
TCP的三次握手
5、發起HTTP請求
6、服務器處理請求
7、服務器響應HTTP請求
8、客戶端解析返回數據
9、與服務器斷開連接
TCP的四次揮手
https://blog.csdn.net/weixin_43844718/article/details/126975557
60、swoole的了解
技術特點:
1 常駐內存,避免重復加載帶來的性能損耗,提升海量性能;
2 基于epoll,輕松支持高并發;
3 協程異步I/O,提高對I/O密集型場景并發處理能力;
4 支持多種通信協議,方便地開發 Http、WebSocket、TCP、UDP 等應用
61、swoole與php-fpm對比有哪些優缺點?
優點:
1 常駐內存的 cli 運行模式,不用每次請求加載一次項目代碼
2 大大提高了對連接請求的并發能力
3 協程異步I/O,提高對I/O密集型場景并發處理能力
4 支持多種通信協議,能搭建 TCP/UDP/UnixSocket 服務器
5 原生支持毫秒定時器
缺點
1 相關文檔較少
2 不支持 xdebug,不支持手動 dump,不熟悉相關工具的話,不太方便調試
3 入門難度高,多數 phper 不了解 TCP/IP 網絡協議、多進程 / 多線程、異步 io 等
62、Nginx+Php-fpm運行原理
http://www.test.cc
|
Nginx
|
路由到 http://www.test.cc/index.php
|
加載nginx的fast-cgi模塊
|
fast-cgi監聽127.0.0.1:9000地址
|
www.test.com/index.php請求到達127.0.0.1:9000
|
php-fpm 監聽127.0.0.1:9000
|
php-fpm 接收到請求,啟用worker進程處理請求
|
php-fpm 處理完請求并撤消內存,返回給nginx
|
nginx 將結果通過http返回給瀏覽器
63、遇到一個網站打開慢怎么排查
1.打不開,則ping域名,看是否能請求成功。
2.慢,說明能打開,直接走這一步,free/top命令查看服務器內存和CPU使用情況,iftop等工具查看帶寬
3.chrome的debug->network查看響應慢的
4.排查響應慢的接口代碼,看php,mysql,redis等的日志看錯誤信息(mysql的慢查詢日志功能,php-fpm慢日志功能,需要配置開啟)
64、高并發解決方案
1、流量優化
防盜鏈處理(去除惡意請求)
2、前端優化
(1) 減少HTTP請求[將css,js等合并]
(2) 添加異步請求(先不將所有數據都展示給用戶,用戶觸發某個事件,才會異步請求數據)
(3) 啟用瀏覽器緩存和文件壓縮
(4) CDN加速
(5) 建立獨立的圖片服務器(減少I/O)
3、服務端優化
(1) 頁面靜態化
(2) 并發處理
(3) 隊列處理
4、數據庫優化
(1) 數據庫緩存
(2) 分庫分表,分區
(3) 讀寫分離
5、web服務器優化
(1) 分布式部署
集群
(2) 負載均衡
65、如何選擇消息隊列?
https://blog.mimvp.com/article/47038.html
66、什么是MQ?
mq是一個消息隊列,其主要目的是為了解決傳統的消息傳輸上管理困難,效率不高的問題.
mq有三大優點:解耦,異步,削峰.
解耦: 如果是傳統的消息通訊方式,無論是哪一方都要去維護一份供外部通訊的這個一個接口,而且各方處理消息的能力有限,效率上明顯跟不上,并且這樣子二者之間的耦合度非常高,對于拓展管理方面極不友好,而是要了mq就不一樣,發送方只需要將消息發送給mq就可以了,別的不用考慮,接口什么的由mq去維護,接收方也只需要去mq里消費消息就可以了,就需要其他開銷,一切由mq中間件來做,達到了解耦操作.
異步: 使用mq,還可以達到異步效果,極大地提升了消息傳輸的效率.發送方在發送消息后不需要關心消費方是否能消費完成,還可以繼續發送其他消息.
削峰:如果是傳統的消息通訊,一下子有大量的消息發送給接收方,這樣對于接收方的處理壓力是很大的,而我們剛好可以利用mq達到一個緩沖操作,一旦流量超出了接收方處理范圍,不用擔心,只需要慢慢消費即可,像經典的雙十一,就很容易會使用到mq這么一個優點.
雖然mq有三大優點,但是我們還是得關心其一些缺點:
因為增加了中間件,系統復雜度肯定大大提高,增加了很多維護的成本,比如我們要保證消息不丟失(一致性)和消息冪等性問題,還要保證mq的高可用等.
67、mq消息隊列如何保證消息的可靠性傳輸
消息的可靠性傳輸分為兩個問題,一個是保證消息不被重復消費,另一個是保證消息不丟失.
保證消息不重復被消費,就是保證消息的冪等性問題,消息的冪等性是指一個操作執行任意多次所產生的影響均與一次執行的影響相同,在mq里,也就是消息只能被消費一次,不能被重復消費.
來看看消息丟失的場景:
發送方丟失,可能發送方在發送消息的過程中,出現網絡問題等導致mq接收不到消息,導致了消息丟失.
要解決這個問題,首先可以采用事務機制,在發送消息的時候實現事務機制,若是出現發送失敗的情況,可以進行回滾,而讓消息重新被發送.但是開啟了事務,發送方就必須同步等待事務執行完畢或者回滾,導致消息一多,性能會下降.
但是,還有一個更好的辦法:可以采用確認機制,發送方在發送消息的時候必須要保證要收到一個確認消息,如果沒有收到或者收到失敗的確認消息,就說明消息發送失敗,要重新進行發送,確認機制是可以采用異步進行的,這樣就極大地保證了在保留效率的基礎上又能保證消息的不丟失問題.
第二個丟失問題可能是在mq方發生的,如果mq沒有進行持久化,出現了宕機關機等情況,消息就會丟失,解決辦法無非就是將消息進行持久化,這樣在出現問題的時候可以及時對消息進行恢復.
第三個丟失問題可能在消費方發生,這和發送方丟失問題類似,解決這個問題也是采用確認機制,這樣一來就可以實現效率上的保證和消息不丟失的保證.
但是解決了這些問題,就會產生下面的冪等性問題:
我們都知道mq是可以進行重發的,且只有在它認為失敗的情況會進行重發.什么時候mq會認為它發送給消費者的消息是失敗的呢?也就是超出了它等待消費者響應的時間,這是一個超時時間,若是過了這個時間消費者仍然沒有響應,說明mq發送失敗,就會進行重試,而其實這個時候消費者可能是沒有失敗的,它只是因為某個原因導致消費超出了mq的等待時間而已,這個時候mq再發送一次消息,消費者就會重復消費.
實現冪等性消費:
MQ相關面試題
https://blog.csdn.net/weixin_47303191/article/details/124693751
MongoDB相關面試題
https://blog.csdn.net/KangJinXuan/article/details/126936926
68、進程、線程、協程區別
進程擁有自己獨立的堆和棧,既不共享堆,亦不共享棧,進程由操作系統調度。
線程擁有自己獨立的棧和共享的堆,共享堆,不共享棧,線程也由操作系統調度。
協程和線程一樣共享堆,不共享棧,協程由程序員在代碼里調度。