寫在前面
休息幾個月,感受了下今年求職的環境到底有多糟糕,後面有時間再吐槽當前環境的各種坑吧。。。
順手記錄下自己簡單整理的php面試知識點,希望對你多有幫助!
僅供參考!!!
Nginx相關
簡介
Nginx是一個開源的”高效能代理伺服器(可以處理數千個併發且迅速響應)”,採用非同步非阻塞的事件驅動模型實現了高可用(高效能、低消耗、可靠穩定)。常用於Web伺服器、負載均衡、反向代理以及靜態資源快取等。
重要的配置檔案
1.nginx.conf:主要的Nginx配置檔案,包含全域性性的設定,例如程式數、工作模式等。該檔案位於/etc/nginx/目錄下。
2.sites-available/default:預設的虛擬主機配置檔案。該檔案位於/etc/nginx/sites-available/目錄下。
3.sites-available/:存放了用於配置不同虛擬主機的配置檔案,每個檔案對應一個虛擬主機。可以在該資料夾下建立新的配置檔案以配置更多的虛擬主機。
4.sites-enabled/:存放了啟用的虛擬主機的配置檔案的符號連結。通常使用ln -s命令將sites-available/目錄下的配置檔案連結到sites-enabled/目錄,從而啟用該虛擬主機。
5.conf.d/:該資料夾下存放了其他Nginx配置檔案的目錄,這些配置檔案可以包含在主配置檔案中。可以在該資料夾下建立新的配置檔案以新增其他配置選項。
常用的命令
1.啟動Nginx:nginx -s start
2.停止Nginx: nginx -s stop
3.重啟Nginx: nginx -s restart
4.檢查Nginx配置檔案是否正確: nginx -t
5.開啟Nginx主程式PID檔案: nginx -s reopen
6.關閉Nginx,並在處理完當前請求後退出: nginx -s quit
7.重新載入配置檔案:nginx -s reload
配置反向代理伺服器
開啟Nginx的配置檔案: /etc/nginx/nginx.conf
配置反向代理:在 Nginx 配置檔案中找到 http 部分,並配置反向代理:
http {
server {
listen 80;
# 域名
server_name demo.com;
# 代理的後端伺服器地址
location / {
proxy_pass http://backend-server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwardeed_for;
}
}
# 後端伺服器地址,可以按需新增多個
upstream backend-server {
server backend1.demo.com;
server backend2.demo.com;
}
}
檢查配置: sudo nginx -t ,並重啟:sudo service nginx restart,反向代理伺服器配置成功!
負載均衡配置
解決問題: 在併發或服務繁忙等場景下,實現速度和穩定性(高可用)
原理:透過反向代理來實現的負載均衡
策略/演演算法:
1.輪詢(預設)
2.IP_HASH演演算法(保持會話,解決會話問題)
3.Weighted演演算法(按權重比例分配伺服器,解決差異性的伺服器效能問題)
4.URL_HASH演演算法(通常用於靜態資源代理,配合快取命中來使用,類似cdn)
IP/IP段控制
限制特定IP地址或IP地址段的訪問,使用Nginx的ngx_http_access_module模組提供的allow和deny指令
# 注意allow, deny順序配置
location / {
# 允許訪問
allow 192.168.1.0/24;
allow 10.0.0.0/16;
# 拒絕訪問
deny all;
}
HTTP與HTTPS的區別以及nginx如何支援?
區別:
1.埠:http 80, https :443
2.狀態:http無狀態,https是有http + ssl身份驗證
3.傳輸方式:http明文傳輸,https加密傳輸
4.連線速度:http更快(三次握手),https 需要12個包(http的3次握手+9個ssl握手包)
支援:nginx 直接配置證照即可。
#透過rewrite將所有HTTP請求重定向HTTPS
server {
listen 80;
server_name demo.com;
rewrite ^(.*)$ https://$server_name$1; 。
}
#ssl證照配置有關。
server {
#埠為443。
listen 443 ssl;
#證照繫結的域名。
server_name demo.com;
charset utf-8;
#證照路徑配置
ssl_certificate /home/you_path/demo.com.pem;
ssl_certificate_key /home/you_path/demo.com.key;
#ssl演演算法相關配置
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
# 其他配置
...
}
靜態檔案快取與壓縮
1.快取相關的配置項,proxy_cache_*
2.gzip壓縮的配置項,gzip_*
nginx日誌
1.配置日誌: access_log,error_log
2.自定義日誌格式(可配置變數參考手冊),如自定義mylog格式:
#時間、客戶端IP、請求方法和URL
log_format mylog ‘$time_local $remote_addr $request_method $request_uri’;
#定義日誌使用自定義的格式
access_log /var/log/nginx/access.log mylog;
限流與最佳化
1.反向代理伺服器,可以隱藏真實伺服器的IP地址,有一定的保護作用。
2.HTTP限制:使用limit_req和limit_conn,對客戶端進行合理的請求限制。
3.訪問限制:使用GeoIP和IP黑名單等,對惡意IP進行攔截或限制。可以基於地理位置、IP地址段等限制。
4.負載均衡:透過反向代理功能,將請求分散到多個後端伺服器上,從而分攤請求壓力。
5.動靜分離:將動態和靜態資源分開,靜態可用Nginx的快取功能快取,減輕後端伺服器壓力。
6.配置防火牆:結合Nginx與防火牆工具(如iptables),對流量進行控制,只允許合法的,阻止惡意流量。
7.監控分析:監控(Nginx Stub Status模組 + 第三方工具),分析(ELK)。問題及時發現處理
PHP相關
cgi
CGI 是 nginx 和 php 通訊的協議。nginx 伺服器在接受請求後,如果是靜態請求(圖片,檔案等無需php處理的)則會直接返回給瀏覽器。如果是一個動態的php請求,nginx 就會透過cgi協議與 php 通訊,將請求資料轉換成 php 能理解的資訊,php 處理完成也透過 cgi 協議返給 nginx,最後 nginx 再返回給瀏覽器。
fast-cgi
傳統的 cgi 協議在每次連線請求時,會開啟一個程式進行處理,處理完畢會關閉該程式。下次請求又重複開啟與關閉。頻繁的程式啟動與關閉,消耗大量的資源和記憶體。而 fast-cgi 每次處理完請求後,不會 kill 掉這個程式,而是保留程式,使程式可以處理多次請求,不用重新 fork 一個程式,大大提高效率。
php-cgi
php-cgi 是 php 提供給 web serve 的 cgi 協議介面程式,每次請求都會開啟一個 php-cgi 程式進行處理,而且開啟php-cgi 會先過載配置,資料結構以及初始化執行環境,如果更新了 php 配置,那麼就需要重啟 php-cgi 才能生效,例如 phpstudy 就是這種情況。
php-fpm
1.php-fpm 是 php 提供給 web serve 的 fastcgi 協議介面程式,是 php-cgi 的一個管理程式。
2.php-fpm 常駐記憶體,會開啟多個 php-cgi 程式,請求來的時候,php-fpm 將連線分配給一個 php-cgi 子程式處理,處理完畢後 php-cgi 並不會關閉,而是等待處理下一個連線,這也是 fast-cgi 加速的原理。
3.php-fpm 是多程式的,一個 php-cgi 大概消耗 7-25M 記憶體,需注意連線過多導致記憶體消耗過大的問題。
4.php-fpm支援平滑啟動,如果更新了 php 配置可使用 /you_path/php-fpm reload 平滑過渡。
php-fpm最佳化
PHP-FPM預設使用靜態程式管理模式(啟動時建立固定數量的程式)
在高負載環境下,推薦使用動態程式管理模式(動態建立/銷燬程式以提高效能)
vim /etc/php-fpm.conf
# 增加程式數
pm.max_children = 50 //pm.max_children表示最大的程式數
pm.start_servers = 20 //pm.start_servers表示啟動時的程式數
# 調整程式空閒時間
pm.max_spare_servers = 10 //pm.max_spare_servers表示空閒程式的最大數量
pm.min_spare_servers = 5 //pm.min_spare_servers表示空閒程式的最小數量
# 每個程式允許處理的最大請求次數。到該次數後程式重啟,釋放資源(大了可能會記憶體溢位,小了頻繁重啟)
pm.max_requests = 1000
# 使用動態程式管理模式(static和dynamic)
pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 10
Nginx 和 php 之間的通訊
1.tcp socket ,面向連線的協議,更好的保證通訊的正確性和完整性
2.unix socket,不需要網路協議打包拆包,開銷小效率高,但高併發時候不穩定,可能返回異常。
網路7層協議模型
應用層、表示層、會話層、傳輸層、網路層、(資料)鏈路層、物理層。快記:應表會傳(物鏈網)
TCP 和 UDP 的特點和區別
1.都是屬於傳輸層協議
2.TCP,面向連線,一對一,資料可靠不丟失
3.UDP,無連線,一對多/多對多,速度更快但不可靠
TCP 的三次握手和四次揮手
1.三次握手:
1.第一次:客戶端傳送SYN = 1,seq = client_isn
2.第二次:服務端傳送SYN = 1,seq = server_isn,ACK =client_isn +1
3.第三次:客戶端傳送SYN = 0, ACK = server_isn+1,seq =client_isn+1
2.四次揮手
1.第一次:客戶端傳送FIN
2.第二次:服務端傳送ACK
3.第三次:服務端傳送FIN
4.第四次:客戶端傳送ACK
HTTP 狀態碼
- 1xx:請求進行中,伺服器收到請求,需要請求者繼續操作
- 2xx:成功
- 3xx:重定向
- 4xx:客戶端錯誤
- 5xx:服務端錯誤
oop是什麼?
物件導向程式設計是一種計算機程式設計架構思想,指程式由一個個能夠起到子程式作用的單元或物件組成。 物件導向3大特性:繼承、封裝、多型。php垃圾回收機制
“引用計數方式(is_ref_gc=0時回收)” + “標記清除方式(解決迴圈引用時回收)”來進行垃圾回收。什麼是引用傳遞?
引用傳遞:函式內對值的任何改變在函式外部也生效(傳遞地址)
值傳遞:函式內對值的任何改變在函式外部不生效(複製值) 對大型字串和物件來說,複製操作代價很大。引用傳遞會有不錯的效能提升(物件預設為引用傳遞)。設計模式五大原則
單一職責原則:單一職責原則可以看做是低耦合、高內聚在物件導向原則上的引申,將職責定義為引起變化的原因,以提高內聚性來減少引起變化的原因。
開放封閉原則:核心理念“對擴充套件開放,對修改封閉”。設計時要允許現有程式碼進行擴充套件,而不是透過修改現有程式碼來實現新的功能。這樣做可以避免對現有程式碼造成不必要的破壞和風險,同時也可以提高程式碼的複用性和可維護性,從而降低開發和維護成本。
介面隔離原則:不要強迫客戶使用它們不用的方法,如果強迫使用者使用它們不使用的方法,那麼這些客戶就會面臨由於這些不使用的方法的改變所帶來的改變。
依賴倒置原則:物件導向而不是程式導向。程式要依賴於抽象介面,不要依賴於具體實現。簡單的說就是要求對抽象進行程式設計,不要對實現進行程式設計,這樣就降低了客戶與實現模組間的耦合。
里氏替換原則:子類可以擴充套件父類的功能,但不能改變父類原有的功能 。
附:迪米特原則:一個物件應該對其他物件保持最少的瞭解。
常見的設計模式
單例模式、工廠模式、觀察者模式、外觀模式、代理模式…
1.建立型模式共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
2.結構型模式共七種:介面卡模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
3.行為型模式共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、直譯器模式。
單例模式:確保一個類只有一個例項,而且自行例項化並向整個系統提供這個例項。
public static function getInstance()
{
return new static();
}
觀察者模式:定義了物件之間的一對多依賴,這樣一來,當一個物件改變狀態時,它的所有依賴者都會收到通知並且有所作為。即出版者+訂閱者=觀察者模式。
工廠模式 :呼叫者和建立者分離,呼叫者直接向工廠類請求獲取物件,減少程式碼耦合,提高系統的維護性和擴充套件性。
介面卡模式:把對某些相似的類的操作轉化為一個統一的“介面”(比喻的說法)–介面卡,或者比喻為一個“介面”,統一或遮蔽了那些類的細節。介面卡模式還構造了一種“機制”,使“適配”的類可以很容易的增減,而不用修改與介面卡互動的程式碼,符合“減少程式碼間耦合”的設計原則。
氣泡排序/快速排序
氣泡排序是一種交換排序。對陣列進行多輪冒泡,每一輪對陣列中的元素兩兩比較,調整位置,冒出一個最大的數來。
/**
* 氣泡排序
* @param array $arr
*/
function bubbleSort(array $arr) : array
{
$length = count($arr);
// 外層迴圈,從陣列首部開始,每完成一次迴圈,可確定 $arr[$i] 位置的元素
for ($i = 0; $i < $length; $i++){
// 內層迴圈,$j 從後往前迴圈
for ($j = $length - 1; $j > $i; $j--) {
// 若前面的值大於後面的值,則互換位置
if ($arr[$j] < $arr[$j - 1]) {
[$arr[$j], $arr[$j - 1]] = [$arr[$j - 1], $arr[$j]];
}
}
}
return $arr;
}
快速排序:遞迴演演算法。先選擇陣列的第一個元素作為標準,然後把小於或等於它和大於它的數分別放入兩個陣列中,對這兩個陣列也進行相同的處理,最後合併這兩個陣列和第一個元素。
/**
* 快速排序
* @param $arr
*/
function quickSort(&$arr) : void
{
$length = count($arr);
// 若陣列為空,則不需要執行
if ($length <= 1) {
return;
}
$middle = $arr[0]; // 選定一箇中間值
$left = []; // 接收小於中間值
$right = [];// 接收大於中間值
// 迴圈比較
for ($i = 1; $i < $length; $i++) {
if ($middle < $arr[$i]) {
$right[] = $arr[$i]; // 大於中間值
} else {
$left[] = $arr[$i]; // 小於或等於中間值
}
}
// 遞迴排序劃分好的左右兩邊
quickSort($left);
quickSort($right);
$arr = array_merge($left, [$middle], $right);
}
單點登入
單點登入(Single Sign On, SSO)是指一次登入即可訪問所有相互信任的應用系統。本質是多個應用系統共享登入狀態。
實現方式一:父域 Cookie。
1.Cookie 的作用域由 domain 屬性和 path 屬性共同決定。所以可以透過把登入狀態的seesion_id 存在主域名域下(當前域的父域),所有子域名就都可以共享了。
2.此種實現方式比較簡單,但不支援跨主域名。
實現方式二:認證中心。
1.部署一個認證中心,專門負責處理登入請求的獨立的 Web 服務。
2.使用者統一在認證中心進行登入,登入成功後,認證中心記錄使用者的登入狀態,並將 Token 寫入 Cookie。(注意這個 Cookie 是認證中心的,應用系統是訪問不到的)
3.應用系統檢查當前請求有沒有 Token,如果沒有,那麼就跳轉至認證中心。而認證中心透過自動攜帶的 Cookie 判斷是否已經登入。
4.如果認證中心發現使用者尚未登入,則返回登入頁面,等待使用者登入。如果發現使用者已經登入過了,就跳轉回目標 URL (目標應用系統),並攜帶回傳一個認證中心的 Token。
5.應用系統拿到 Token 之後,後端向認證中心確認下 Token 的合法性,防止使用者偽造的同時check使用者登入狀態。確認無誤後,應用系統記錄使用者的登入狀態,並將 Token 寫入 Cookie,訪問放行。(此時Cookie 是當前應用系統的)當使用者再次訪問當前應用系統時,就會自動帶上這個 Token,應用系統驗證 Token,就實現了單點登入。
6.此種實現方式相對複雜,但支援跨域,擴充套件性好,是單點登入的標準做法。
實現方式三:LocalStorage 跨域。
1.在這樣的場景下,單點登入完全可以在前端實現。前端拿到 Session ID (或 Token )後,除了將它寫入自己的 LocalStorage 中之外,還可以透過特殊手段將它寫入多個其他域下的 LocalStorage 中。
2.前端將同一份 Token 寫入到了多個域下的 LocalStorage 中,前端每次在向後端傳送請求之前,都會主動從 LocalStorage 中讀取 Token 並在請求中攜帶,這樣就實現了同一份 Token 被多個域所共享。
3.此種實現方式完全由前端控制,幾乎不需要後端參與,同樣支援跨域。但擴充套件性不好,不利於維護。
php的堆與棧
1.heap是堆,stack是棧;
2.heap上的空間手動分配/釋放(程式執行時分配的記憶體),stack的空間由作業系統自動分配/釋放(程式執行時為函式、區域性變數等分配的記憶體空間);
3.zendVM中的malloc函式分配的記憶體空間即在堆上(mm_heap)
在PHP中,Zend引擎透過記憶體分配器來管理堆記憶體的分配和釋放。當PHP執行過程中需要分配更多記憶體時,記憶體分配器會從堆中分配一塊足夠大的空間,供變數和資料結構使用。而當某個變數或資料結構不再使用時,記憶體分配器會將相應的記憶體空間返回給堆。
php底層相關理解
通常就是問:符號表(hashTable)、zvalue結構體、zend vm的記憶體分配等
php的執行模式
CGI 模式(phpstudy、wnmp)
FastCGI 模式(lnmp最常見的環境)
CLI 模式(php命令列)
web模組模式( Apache )
PHP實現靜態化
PHP的靜態化分為:純靜態和偽靜態。其中純靜態又分為:區域性純靜態和全部純靜態。
PHP偽靜態:利用Apache mod_rewrite,niginx rewrite 實現URL重寫的方法;
PHP純靜態:生成HTML檔案的方式,須開啟PHP自帶的快取機制,即ob_start來開啟快取。
session和cookie
session和cookie是一種會話管理技術,通常把session_id存在cookie來匹配管理會話。
儲存位置:cookie在客戶端,session在伺服器
儲存容量:單個cookie資料<=4KB,一個站點最多儲存20個Cookie; session理論沒有限制(存重要資訊即可)
安全性與其他:cookie在客戶端不安全(佔用客戶端資源),session在伺服器安全(佔用伺服器資源)
CSRF攻擊,XSS攻擊
CSRF(Cross-site request forgery)跨站請求偽造,駭客建立一個偽造網站或傳送郵箱帶了一個正常URL連結來讓正常使用者訪問,來讓使用者透過自己瀏覽器裡的COOKIE許可權來執行一些非法請求
防範方法有:驗證 HTTP Referer 欄位、新增 token 並驗證;
XSS攻擊
主要將XSS程式碼提交儲存在伺服器端(資料庫,記憶體,檔案系統等),下次請求目標頁面時不用再提交XSS程式碼。當目標使用者訪問該頁面獲取資料時,XSS程式碼會從伺服器解析之後載入出來,返回到瀏覽器做正常的HTML和JS解析執行,XSS攻擊就發生了。
防範方法:透過過濾是針對非法的HTML程式碼包括單雙引號等,使用htmlspecialchars()函式
抽象類和介面分別是什麼?
抽象類:就是一種特殊的類,不能被例項。可以定義方法,屬性。類似於模版,規範後讓子類實現詳細功能。
介面:主要基於方法/物件的規範。可讓某個類透過實現多個介面來形成新的類。
抽象類與介面的相同點:
1.都是用於宣告某一種事物,規範名稱、引數,形成模組,未有詳細的實現細節。
2.都是透過類來實現相關的細節
3.語法上,抽象類的抽象方法與介面一樣,不能有方法體,即{}符號
4.都可以用繼承,介面繼承介面形成新的介面,抽象類繼承抽象類形成新的抽象類
抽象類與介面的不同點:
1.抽象類可以有屬性、普通方法、抽象方法,但介面不能有屬性、普通方法(可以有常量)
2.抽象類內未必有方法定義(可以都是普通方法),但介面內一定會有“方法定義”
3.抽象類用abstract關鍵字,class宣告為類,介面用interface宣告
4.抽象類的抽象方法一定要用abstract來宣告,而介面不需要
5.抽象類是用extends關鍵字讓子類繼承,介面用implements實現介面
網站效能最佳化/高併發解決方法
1.前端最佳化
減少HTTP請求[將css,js等合併]
新增非同步請求(非必須資料先不展示,使用者觸發某個事件才會非同步請求資料)
CDN加速,建立獨立的檔案/圖片伺服器(減少I/O)
2.web伺服器最佳化
防盜鏈處理(去除惡意請求)
反向代理實現負載均衡
靜態資源快取和gzip壓縮
流量過濾,ip限制及黑白名單
3.應用程式最佳化
業務程式碼邏輯檢查最佳化,sql查詢最佳化
常駐記憶體swoole,opcache快取技術,連線池技術
4.資料庫最佳化
讀寫分離,負載均衡
redis快取、資料庫快取策略
分表分割槽分庫,資料拆分
表結構最佳化,索引最佳化
防止sql注入
驗證資料,可以根據相應型別進行嚴格的驗證。比如 int 型別直接同過 intval 進行轉換; 引數化繫結,PDO引數繫結,禁止使用sql拼接;mysql開啟嚴格模式;
8大魔術常量
1.LINE:檔案中 本常量所在行的 行號(即處於第幾行)。
2.FELE:本檔案的完整路徑和檔名。如果被用在 被包含檔案中,則返回被包含檔案的檔名。本常量總是包含一個絕對路徑(如果是符號連結,則是解析後的絕對路徑)
3.DIR:本檔案所在目錄。如果被用在 被包含檔案中,則返回被包含檔案的所在目錄。它等價於 dirname(FILE)。除非是根目錄,否則目錄名中不包含末尾的斜槓。
4.FUNCTION:函式名稱。自PHP5起本常量返回函式被定義時的名稱(區分大小寫)。
5.CLASS:類名稱。自PHP5起本常量 返回類被定義時的名稱(區分大小寫,包括其名稱空間。如:Foo\Bar)。
6.TRAIT:trait 的名稱。自 PHP5.4 起本常量返回 trait 被定義時的名稱(區分大小寫)。
7.METHOD:類的方法名。返回該方法被定義時的名稱(區分大小寫)。
8.NAMESPACE:當前名稱空間的名稱(區分大小寫)。本常量是在編譯時定義的。
9個超全域性變數
1.$_GLOBALS :儲存全域性作用域中的變數
2.$_SERVER :獲取伺服器相關資訊
3.$_REQUEST:獲取POST和GET請求的引數
4.$_POST : 獲取表單的POST請求引數
5.$_GET: 獲取表單的GET請求引數
6.$_FILES :獲取上傳檔案的的變數
7.$_ENV : 獲取伺服器端環境變數的陣列
8.$_COOKIE:獲取瀏覽器的cookie
9.$_SESSION : 獲取session
魔術方法
constuct構建物件的時被呼叫;
__destruct明確銷燬物件或指令碼結束時被呼叫;
__set當給不可訪問或不存在屬性賦值時被呼叫
__get讀取不可訪問或不存在屬性時被呼叫
__isset對不可訪問或不存在的屬性呼叫isset()或empty()時被呼叫
__unset對不可訪問或不存在的屬性進行unset時被呼叫
__call呼叫不可訪問或不存在的方法時被呼叫
__callStatic呼叫不可訪問或不存在的靜態方法時被呼叫
__sleep當使用serialize時被呼叫,當你不需要儲存大物件的所有資料時很有用
__wakeup當使用unserialize時被呼叫,可用於做些物件的初始化操作
__clone進行物件clone時被呼叫,用來調整物件的克隆行為
__toString當一個類被轉換成字串時被呼叫
__invoke當以函式方式呼叫物件時被呼叫
__set_state當呼叫var_export()匯出類時,此靜態方法被呼叫。用set_state的返回值做為var_export的返回值。
__debuginfo當呼叫var_dump()列印物件時被呼叫(當你不想列印所有屬性)
請求的生命週期
1.構建請求
2.查詢本地快取
3.域名解析
4.與伺服器建立連線(TCP的三次握手)
5.發起HTTP請求
6.伺服器處理請求
7.伺服器響應HTTP請求
8.客戶端解析返回資料
9.與伺服器斷開連線(TCP的四次揮手)
網站開啟慢怎麼排查
1.打不開,則ping域名,看是否能請求成功。
2.慢,說明能開啟,直接 free/top命令檢視伺服器記憶體和CPU使用情況,iftop等工具檢影片寬
3.chrome的debug->network檢視響應慢的請求
4.排查響應慢的介面程式碼,看php,mysql,redis等的日誌看錯誤資訊(mysql的慢查詢日誌,php-fpm慢日誌,需要配置開啟)
什麼是MQ?
mq是一個訊息佇列,通常是解決傳統的訊息傳輸上管理困難,效率不高的問題。
mq有三大優點:解耦,非同步,削峰
缺點: 增加了中介軟體,就提高了系統複雜度,增加了維護的成本。比如:要保證訊息不丟失(一致性)和訊息冪等性問題,還要保證mq的高可用等
Mysql相關
資料庫三大正規化是什麼?
第一正規化:1NF是對屬性的原子性,要求屬性具有原子性,不可再分解;
第二正規化:2NF是對記錄的唯一性,要求記錄有唯一標識,即實體的唯一性,即不存在部分依賴;
第三正規化:3NF是對欄位的冗餘性,要求任何欄位不能由其他欄位派生出來,它要求欄位沒有冗餘,即不存
MyISAM與InnoDB的區別
1.MyISAM不支援事務與外來鍵,InnoDB 支援。
2.MyISAM是表鎖,InnoDB行鎖(提高了併發效能)。
3.MyISAM表是儲存成獨立檔案的形式,在資料轉移、備份MyISAM更具有優勢。
4.AUTO_INCREMENT:MyISAM 可以和其他欄位一起建立聯合索引,InnoDB中必須是隻有該欄位的索引
5.MyISAM支援 FULLTEXT型別的全文索引,InnoDB不支援,但外掛sphinx支援全文索引(效果更好)。
6.MyISAM允許沒有任何索引和主鍵的表存在,InnoDB沒有主鍵會選擇非空唯一索引,或自動生成一個6位的uuid主鍵
7.MyISAM的SELECT效能更好,InnoDB的INSERT、UPDATE、DELETE 更好(刪除全表使用truncate table)
8.索引區別:
聚簇索引:索引和資料儲存在一個節點
非聚簇索引:索引和資料分開儲存,透過索引找到資料實際儲存的地址
innodb 使用的聚簇索引,主鍵索引為聚簇索引(沒有主鍵索引會選擇一個非空唯一索引或隱式的建立一個主鍵索引),輔助索引指向主鍵索引,然後再找到實際儲存地址
myisam 使用非聚簇索引(輔助索引和主鍵索引一樣),都只需要查詢一次就能找到資料
聚簇索引的優勢和略勢:
1.索引和資料在一起,同一頁的資料會被快取到(buffer)記憶體中,所以檢視同一頁資料的時候只需要從記憶體中取出
2.資料更新之後之只需要維護主鍵索引即可,輔助索引不受影響
3.輔助索引存的是主鍵索引的值,容易產生回表
4.使用隱式的uuid主鍵時,資料分佈不均勻,導致聚簇索引可能掃全表,效率低下(強制使用自增主鍵id )
備註:b-tree(mongodb) 和 b+tree (mysql)的區別:
1.b+tree 的資料全部儲存在葉子節點,主節點只存key,一次磁碟IO能獲取到更多的節點
2.b+tree 增加了葉子節點到相鄰節點的指標,資料是有序雙向連結串列 ,方便返回查詢範圍(順序性)
3.b-tree 的主節點和葉子節點都儲存key和資料,查詢資料不需要找到葉子節點,主節點可以直接返回資料
事務的ACID與隔離級別
事務遵循包括原子性在內的 ACID 四大特性:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和永續性(Durability);
原子性 :資料提交工作時,要麼保證所有的修改都能夠提交,要麼就所有的修改全部回滾。
一致性:資料庫從一個一致性狀態變換到另一個一致性狀態。
隔離性: 如果多個事務併發執行,應像各個事務獨立執行一樣。
永續性:一個成功執行得事務對資料庫得作用是持久的,即使資料庫發生故障出錯,也應該能夠恢復
四種隔離級別:
1.未提交讀(read-uncommitted)所有事務都可以看到其他未提交事務的執行結果。很少用於實際應用,因為它的效能也不比其他級別好多少。會產生髒讀,不可重複讀以及幻讀
2.已提交讀(read-committed)這是大多數資料庫系統的預設隔離級別(但不是 MySQL 預設的)。它滿足了隔離的簡單定義:一個事務只能看見已經提交事務所做的改變。會產生幻讀
3.可重複讀(repeatable-read)這是 MySQL 的預設事務隔離級別,它確保同一事務的多個例項在併發讀取資料時,會看到同樣的資料行。不過理論上,也會導致幻讀 (Phantom Read)。幻讀指當使用者讀取某一範圍的資料行時,另一個事務又在該範圍內插入了新行,當使用者再讀取該範圍的資料行時,會發現有新的 “幻影” 行。InnoDB 儲存引擎透過多版本併發控制(MVCC,Multiversion Concurrency Control)機制解決了該問題。
4.序列化(serializable)這是最高的隔離級別,它透過強制事務排序,使之不可能相互衝突,從而解決幻讀問題。簡言之,它是在每個讀的資料行上加上共享鎖。在這個級別,可能導致大量的超時現象和鎖競爭。
MyISAM 表鎖
1.共享讀鎖(S)之間是相容的,但共享讀鎖(S)和排他寫鎖(X)之間,以及排他寫鎖之間(X)是互斥的,也就是說讀和寫是序列的。
2.在一定條件下,MyISAM 允許查詢和插入併發執行,利用這一點來解決應用中對同一表和插入的鎖競爭問題。
3.MyISAM 預設鎖排程機制是寫優先,不一定適合所有應用,可以透過設定 LOW_PRIPORITY_UPDATES 引數,或在 INSERT、UPDATE、DELETE 語句中指定 LOW_PRIORITY 選項來調節讀寫鎖的爭用。
4.由於表鎖的鎖定粒度大,讀寫之間又是序列的,因此,如果更新操作較多,MyISAM 表可能會出現嚴重的鎖等待,可以考慮採用 InnoDB 表來減少鎖衝突。
InnoDB 表
1.InnoDB 的行鎖是基於索引實現的,如果不透過索引訪問資料,InnoDB 會使用表鎖。
2.在不同的隔離級別下,InnoDB 的鎖機制和一致性讀策略不同。
3.MySQL 的恢復和複製對 InnoDB 鎖機制和一致性讀策略也有較大影響。
4.注意死鎖,鎖衝突甚至死鎖很難完全避免。
減少鎖衝突和死鎖
1.儘量使用較低的隔離級別
2.精心設計索引,儘量使用索引訪問資料,使加鎖更精確,從而減少鎖衝突的機會。
3.選擇合理的事務大小,小事務發生鎖衝突的機率也更小。
4.給記錄集顯示加鎖時,最好一次性請求足夠級別的鎖。比如要修改資料的話,最好直接申請排他鎖,而不是先申請共享鎖,修改時再請求排他鎖,這樣容易產生死鎖。
5.不同程式訪問一組表時,應儘量約定以相同的順序訪問,這樣可以減少死鎖的機會。
6.儘量用相等條件訪問資料,這樣可以避免間隙鎖對併發插入的影響。
7.不要申請超過實際需要的鎖級別;除非必須,查詢時不要顯示加鎖。
分表 (分庫) 的策略
根據業務資料量和業務複雜度來拆分,業務拆分可參考:取餘、hash、range範圍; 表結構拆分:垂直、水平。
binlog日誌
通常用與:資料恢復、主從複製
可設定格式: statement 、 row 、 mixed(通常使用 row 或者 mixed )
主從同步
可用於: 實現讀寫分離 、 資料備份高可用、負載均衡提高效能、版本升級測試
流程:
1.從節點開啟start slave 命令之後,建立一個IO程式連線到主節點
2.連線成功之後,主節點建立一個 log dump執行緒(主節點會為每一個從節點創一個log dump執行緒)
3.當binlog發生變化時,主節點的dump log執行緒會讀取bin-log內容併傳送給從節點
4.主節點dump log 執行緒讀取bin-log 的內容時會對主節點的bin-log加鎖,讀取完成在傳送給從節點之前釋放鎖
5.從節點的IO執行緒接收主節點傳送的binlog內容,並將其寫入本地relay log 檔案中
6.主從節點透過binlog檔案+position偏移量定位主從同步的位置,從節點會儲存接收到的position偏移量,如果從節點發生當機重啟,自動從postion位置發起同步
7.從節點的SQL執行緒複製讀取本地relay log的內容,解析成具體的操作並執行,保證主從資料一致性
模式: 非同步模式(預設方式) 、 全同步模式 、 半同步模式 (幾乎不用)
limit 最佳化
1.主鍵閾值法: 透過條件推算出符合條件的主鍵最大值&最小值來避免
2.配合es來分頁
redis 快取和 mysql 資料一致性
1.先更新redis 再更新資料庫
2.先更新資料庫,再更新redis
3.先刪除快取再更新資料庫
問題:以上在併發同時請求時候都有可能出現資料不一致的情況。
解決: 1. 延時雙刪除 ;2. 序列獲取(佇列化),如:查詢佇列+更新佇列
A欄位分組且B欄位最大的資料?
# 表結構:name,type,age
select * from users where (type, age) in (select type, max(age) from users group by type)
order by age desc;
# join操作
SELECT u.* FROM users u
JOIN (
SELECT type, Max(age) AS max_age FROM users GROUP BY type
) t
ON u.type = t.type AND u.age = t.max_age
order by age desc;
欄位值置換更新
對欄位值置換更新,如:欄位status 為0、1,需把1更新為0,0更新為1。
# 數學置換 x = 0 + 1
update `table` set status = 1 - status where 1=1;
# 語法 case when then
UPDATE users
SET type = CASE
WHEN type = 1 THEN 2
WHEN type = 2 THEN 1
ELSE type
END
WHERE 1=1;
Redis相關
redis 資料結構
常見的資料結構型別有:String、List、Set、 Hash、ZSet
redis 為什麼快
Redis 採用的是基於記憶體的單執行緒/多路IO複用模型的 KV 資料庫, 由 C 語言編寫,官方資料QPS達到100000+。
完全基於記憶體,絕大部分請求是純粹的記憶體操作,非常快速。資料存在記憶體中,查詢和操作的時間複雜度都是 O (1); Redis 中的資料結構簡單,對資料操作也簡單; 採用單執行緒,避免了不必要的上下文切換和競爭條件,也不存在多程式或多執行緒的切換而消耗CPU,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,因為沒有可能出現死鎖而導致的效能消耗; 使用多路 I/O 複用模型,非阻塞 IO;多路 I/O 複用模型是利用 select、poll、epoll 可以同時監察多個流的 I/O 事件的能力。在空閒時,會阻塞當前執行緒,當有一個或多個流有 I/O 事件時,就從阻塞態中喚醒,於是程式就會輪詢一遍所有的流(epoll 是隻輪詢那些真正發出了事件的流),並且只依次順序的處理就緒的流,這種做法就避免了大量的無用操作。 這裡 “多路” 指的是多個網路連線,“複用” 指的是複用同一個執行緒。採用多路 I/O 複用技術可以讓單個執行緒高效的處理多個連線請求(儘量減少網路 IO 的時間消耗),且 Redis 在記憶體中運算元據的速度非常快,也就是說記憶體的操作不會成為影響 Redis 效能的瓶頸, 所以造就了 Redis 具有很高的吞吐量。
redis的持久化
RDB 快照(每隔一段時間寫入快照的方式)
AOF( 將每一個收到的寫命令都透過 write 函式追加到 appendonly.aof 檔案)
Redis 記憶體滿了的解決方法
增加記憶體,記憶體淘汰策略,搭叢集
快取穿透,雪崩,預熱/更新
快取穿透:是指使用者查詢資料庫沒有的資料,快取中也不會有。快取中找不到,都要去資料庫再查一遍,然後返回空(進行了兩次無用的查詢)。繞過快取直接查資料庫,也是快取命中率的問題。 解決:攔截查詢或空結果快取
快取雪崩:同一時間大量快取失效,從而資料庫查詢壓力暴增導致服務不可用或當機。 解決:快取過期策略、做多級快取、快取標記等等,總之就是避免同一時間出現大量快取資料過期;
預熱/更新:手動或定時對快取資料進行清理、載入或更新操作。
redis主從哨兵和叢集的區別
一、架構不同
- redis主從:一主多從;
- redis叢集:多主多從;
二、儲存不同 - redis主從:主節點和從節點都是儲存所有資料;
- redis叢集:資料的儲存是透過hash計算16384的槽位,算出要將資料儲存的節點,然後進行儲存;
三、選舉不同 - redis主從:透過啟動redis自帶的哨兵(sentinel)叢集進行選舉,也可以是一個哨兵
- 選舉流程:先發現主節點fail的哨兵,將成為哨兵中的leader,之後的主節點選舉將透過這個leader進行故障轉移操作,從存活的slave中選舉新的master,新的master選舉同叢集的master節點選舉類似;
- redis叢集:叢集可以自己進行選舉
- 選舉流程:
1.當主節點掛掉,從節點就會廣播該主節點fail;
2.延遲時間後進行選舉(延遲的時間演演算法為:延遲時間+隨機數+rank*1000,從節點資料越多,rank越小,因為主從資料複製是非同步進行的,所以 所有的從節點的資料可能會不同),延遲的原因是等待主節點fail廣播到所有存活的主節點,否則主節點會拒絕參加選舉;
3.參加選舉的從節點向所有的存活的節點傳送ack請求,但只有主節點會回覆它,並且主節點只會回覆第一個到達參加選舉的從節點,一半以上的主節點回復,該節點就會成為主節點,廣播告訴其他節點該節點成為主節點。
四、節點擴容不同
1.redis主從:只能擴容從節點,無法對主節點進行擴容;
2.redis叢集:可以擴容整個主從節點,但是擴容後需要進行槽位的分片,否則無法進行資料寫入,命令為:/usr/local/redis-5.0.3/src/redis-cli -a zhuge --cluster reshard 192.168.0.61:8001
MongoDB相關
mongodb是什麼?
MongoDB 是由 C++語言編寫,是一個基於分散式檔案儲存的開源NoSQL資料庫(檔案資料庫)。 再高負載的情況下,新增更多的節點,可以保證伺服器效能。 旨在提供可擴充套件的高效能資料儲存解決方案。mongodb有哪些特點?
1.MongoDB 是一個面向檔案儲存的資料庫,操作起來比較簡單和容易。
2.可以在 MongoDB 記錄中設定任何屬性的索引(如:FirstName=”Sameer”,Address=”8 Gandhi Road”)實現更快排序。
3.可以透過本地或者網路建立資料映象,這使得 MongoDB 有更強的擴充套件性。
4.負載的增加(更多的儲存空間和更強的處理能力),它可以分佈在網路中的其他節點上這就是所謂的分片。
5.MongoDb 支援豐富的查詢表示式。查詢指令使用 JSON 形式的標記,可輕易查詢檔案中內嵌的物件及陣列。
6.MongoDb 使用 update()命令可以實現替換完成的檔案(資料)或者一些指定的資料欄位 。
7.Mongodb 中的 Map/reduce 主要是用來對資料進行批次處理和聚合操作。
8.Map 和 Reduce,Map 函式呼叫 emit(key,value)遍歷集合中的所有記錄,將key與value傳給Reduce函式處理。
9.Map和Reduce函式是用Javascript編寫的,可以透過db.runCommand或mapreduce命令來執行MapReduce操作。
10.GridFS 是 MongoDB 中的一個內建功能,可以用於存放大量小檔案。
11.MongoDB 允許在服務端執行指令碼, 可以用 Javascript 編寫某個函式,直接在服務端執行,也可以把函式的定義儲存在服務端,下次直接呼叫即可。
MySQL與MongoDB之間最基本的差別是什麼?
MySQL和MongoDB兩者都是免費開源的資料庫。MySQL和MongoDB有許多基本差別包括資料的表示(data representation),查詢,關係,事務,schema的設計和定義,標準化(normalization),速度和效能。透過比較MySQL和MongoDB,實際上我們是在比較關係型和非關係型資料庫(資料儲存結構不同)。
MongoDB的特點/為啥是最好的Nosql資料庫?
面向檔案的、高可用(穩定可靠效能)、易擴充套件性、豐富的查詢語言
MongoDB的集合collection
集合就是一組 MongoDB 檔案。它相當於關係型資料庫中的表概念。集合位於單獨的一個資料庫中。一個集合內的多個檔案可以有多個不同的欄位。一般來說,集合中的檔案都有著相同或相關的目的。
MongoDB的檔案Document
檔案由一組key value組成(json)。是動態模式:同一集合裡的檔案可能是不同的欄位和結構。檔案相當於關係型資料庫中table的一條記錄。
什麼是mongod?
mongod是處理MongoDB系統的主要程式。它處理資料請求,管理資料儲存,和執行後臺管理操作。當我們執行mongod命令意味著正在啟動MongoDB程式,並且在後臺執行。
預設埠: “27017”、預設儲存路徑:”/data/db”
MongoDB中的副本集
在MongoDB中副本集由一組MongoDB例項組成,包括一個主節點多個次節點,MongoDB客戶端的所有資料都寫入主節點(Primary),副節點從主節點同步寫入資料,以保持所有複製集記憶體儲相同的資料,提高資料可用性。
Elasticsearch相關
es簡介
一個高擴充套件、生態化、開源的全文檢索引擎,它可以準實時地快速儲存、搜尋、分析海量的資料。全文檢索是指計算機索引程式透過掃描文章中的每一個詞,對每一個詞建立一個索引,指明該詞在文章中出現的次數和位置。當使用者查詢時,檢索程式就根據事先建立的索引進行查詢,並將查詢的結果反饋給使用者。
es查詢流程
1.客戶端請求發給某個節點
2.節點轉發給每個分片,查詢每個分片上的前n條
3.結果返回給節點,合併整合資料,提取前n條
4.最後返回給請求客戶端
ES 為什麼比 mysql 快
es索引存於記憶體之中,採用倒序索引,結構為”分詞<=>id”的方式,能透過分詞快速定位檔案(分詞索引 vs b+tree)
本作品採用《CC 協議》,轉載必須註明作者和本文連結