2022年8月30日 星期二

XAMPP CI3 Git 洩漏?

 許多工程師在撰寫程式時,會使用 Git 來做版本控管,在使用 Git 的時候,目錄底下會產生一個 .git 的隱藏檔案,裡面就是 git repository,會儲存程式的修改、新增、刪除等紀錄。

若工程師直接將含有 .git 目錄的專案放到網頁伺服器的公開目錄,駭客便有可能下載 .git 中的資料,利用 git 的機制將原始碼重建。

因此當工程師開發完成時,可能有兩個方法發佈較為妥當:

額外將網頁程式碼製作一個副本 (不含 .git),再發佈到網頁伺服器。

直接將含 git 目錄的專案放到網頁伺服器,但同時做好網頁的權限控管,也就是當你瀏覽 /.git 底下的全部內容時,會回傳 403。

假如工程師在測試登入功能時,將 admin 的帳密紀錄在程式的註解中,並使用 git 紀錄到歷史版本中,當工程師不小心上傳 .git,並且沒有做權限控管,那麼駭客就能從洩漏的 .git 目錄中拿到帳密。

此外,因為 .git 洩漏是已知且普遍的問題,有眾多工具可以協助駭客下載 .git 目錄並重建原始碼,只要網頁不小心將 .git 上傳,那就有許多人可以將網頁的 .git 下載下來,反倒甚至出現針對這種工具漏洞的攻擊:

攻擊者會構建惡意的 .git 目錄,故意將其中的一些資料路徑修改,例如將文件路徑加上很多 ../../../ ,一旦重建工具沒有檢查路徑,重構資料就可以隨意覆蓋到你的正常檔案。


一般來說,只要網址/.git 可以看到東西,基本上就能將程式還原,但是有時候網址輸入 /.git 會出現 403 (「無權」訪問指定的URL而非 「檔案不存在」,代表 .git 目錄可能是存在的,你可以嘗試 /.git/config,看他有沒有擋),或是用其他方式拿到 .git 的資料,例如下載

網址/.git/logs/HEAD 儲存 git 的 log,可以找到歷史 commit

網址/.git/refs/heads/master 會記錄 master 的 commit hash,可以分解出該 commit 的資料

網址/.git/refs/heads 底下會放所有分支的名字資料夾

網址/.git/refs/stash 用於暫時保存 git 工作進度,可以把做到一半的東西先藏起來(stash),不要 commit 出去

git stash list 顯示 stash 內的所有內容

git stash pop 把剛剛做到一半存在 stash 的資料還原

網址/.git/info/packs packs 的件提取與恢復 (比較少考)

網址/.git/index 會儲存 git add 的資料


<Directory "C:/xampp/htdocs">

    Options Includes FollowSymLinks ExecCGI


    AllowOverride All


    Require all granted

    Header set Access-Control-Allow-Origin *

    RedirectMatch 404 /\\.(svn|git|hg|bzr|cvs)(/|$)

</Directory>


<DirectoryMatch "^/.*/\.git/">

    Order allow,deny

    Require all denied

</DirectoryMatch>

2022年3月9日 星期三

Apache 核心功能 AcceptFilter Directive 深入探討

AcceptFilter 指令簡介

AcceptFilter 是 Apache HTTP 伺服器中一個重要的指令,用於配置伺服器如何接受新的連線請求。它直接影響伺服器的效能,尤其是當伺服器面臨高併發連線時。

AcceptFilter 的作用

  • 控制連線接受方式: AcceptFilter 指令指定了 Apache 如何處理 incoming connections。不同的配置會影響伺服器處理連線的順序和方式。
  • 影響伺服器效能: 合理配置 AcceptFilter 可以提升伺服器的效能,特別是在高併發環境下。
  • 適應不同硬件環境: 不同的硬件配置和作業系統可能需要不同的 AcceptFilter 設定。

AcceptFilter 的值

常見的 AcceptFilter 值有:

  • accept: 這是最基本的配置,按照連線到來的順序依次處理。
  • prefork: 為每個子進程預先分配一個 accept() 鎖,提高處理連線的速度。
  • http: 使用 HTTP 協議的 accept() 系統調用。
  • mPM: 由多處理模組 (MPM) 決定如何處理連線。

不同 AcceptFilter 值的比較

AcceptFilter 值描述優點缺點
accept按順序處理連線配置簡單在高併發下可能導致性能瓶頸
prefork為每個子進程預先分配 accept() 鎖提高連線處理速度可能消耗更多系統資源
http使用 HTTP 協議的 accept() 系統調用可以利用一些 HTTP 特性可能不適用於所有情況
mPM由 MPM 決定靈活性高配置較複雜

如何選擇合適的 AcceptFilter

選擇合適的 AcceptFilter 取決於以下因素:

  • 硬件配置: CPU、記憶體等硬件資源的限制會影響 AcceptFilter 的選擇。
  • 作業系統: 不同的作業系統對 AcceptFilter 的支持可能有所不同。
  • 應用程序需求: 不同的應用程序對連線處理的要求也不同。
  • 伺服器負載: 高併發環境下,需要選擇能高效處理連線的配置。

示例配置

Apache
<IfModule mpm_prefork_module>
    AcceptFilter prefork
</IfModule>

上述配置表示使用 prefork 模式,為每個子進程預先分配 accept() 鎖。

注意事項

  • MPM 的影響: AcceptFilter 的效果會受到 MPM 的影響,不同的 MPM 有不同的特性。
  • 其他配置項: AcceptFilter 只是 Apache 配置的一部分,需要與其他配置項配合使用才能達到最佳效果。
  • 性能測試: 最好的方式是通過性能測試來確定最適合的 AcceptFilter 配置。

總結

AcceptFilter 是 Apache 伺服器中一個重要的配置項,它直接影響伺服器的性能。選擇合適的 AcceptFilter 值需要綜合考慮硬件、軟體、應用程序等多方面的因素。通過合理的配置,可以提升伺服器的性能,提高用戶體驗。

2022年3月8日 星期二

Apache假死堵塞卡死無響應解決方法

 啟用MPM模組配置文件

Apache針對不同的作業系統提供了多個不同的MPM模組,例如:mpm_beos、mpm_event、mpm_netware、mpmt_os2、mpm_prefork、mpm_winnt、mpm_worker。

Windows作業系統上默認的MPM模組是mpm_winnt,mpm_winnt模組是專門針對Windows作業系統而優化設計的MPM模組。它只創建一個單獨的子進程,並在這個子進程中輪流產生多個線程來處理請求。

在對Apache的MPM模組具備一定了解後,我們就可以針對不同的MPM模組來修改Apache的最大並發連接數配置了

修改任何文件,建議做好備份。

apache\conf\httpd.conf文件中啟用該配置文件


# Server-pool management (MPM specific)

Include conf/extra/httpd-mpm.conf (去掉該行前面的注釋符號"#")

對應的配置參數作用如下:


ThreadsPerChild:每個子進程的最大並發線程數。 

MaxRequestsPerChild:每個子進程允許處理的請求總數。如果累計處理的請求數超過該值,該子進程將會結束(然後根據需要確定是否創建新的子進程),該值設為0表示不限制請求總數(子進程永不結束)。 

該參數建議設為非零的值,可以帶來以下兩個好處: 

1. 可以防止程序中可能存在的記憶體泄漏無限進行下去,從而耗盡記憶體。 

2. 給進程一個有限壽命,從而有助於當伺服器負載減輕的時候減少活動進程的數量。

注意:在以上涉及到統計請求數量的參數中,對於KeepAlive的連接,只有第一個請求會被計數。


修改MPM模組配置http-mpm.conf文件中的相關配置


在Apace安裝目錄/conf/extra目錄中有一個名為httpd-mpm.conf


#由於mpm_winnt模組只會創建1個子進程,因此這裡對單個子進程的參數設置就相當於對整個Apache的參數設置。

<IfModule mpm_winnt_module>

ThreadsPerChild 521 #默認值是150,推薦設置:小型網站=1000 中型網站=1000~2000 大型網站=2000~3500

MaxRequestsPerChild 3000 #推薦設置:小=10000 中或大=20000~100000

</IfModule>

再考慮一個可能,(apache 2.4)


apache 2.4 IE10瀏覽器會導致Apache2.4版本阻塞假死,有一種說法,用IE10登錄了網站,導致了apache的卡死,這裡做一個防範:

在配置文件httpd.conf中添加如下兩句


AcceptFilter http none

AcceptFilter https none



原文網址:https://kknews.cc/code/2no3569.html

2022年3月7日 星期一

《面試官別再問》Nginx常見的面試題

1. 什麼是Nginx?

Nginx是一個輕量級/高性能的反向代理Web服務器,他實現非常高效的反向代理、負載平衡,他可以處理2-3萬並發連接數,官方監測能支持5萬並發,現在中國使用nginx網站用戶有很多,例如:新浪、網易、 騰訊等。


2. 為什麼要用Nginx?

跨平台、配置簡單、方向代理、高並發連接:處理2-3萬並發連接數,官方監測能支持5萬並發,內存消耗小:開啟10個nginx才佔150M內存,nginx處理靜態文件好,耗費內存少,

而且Nginx內置的健康檢查功能:如果有一個服務器宕機,會做一個健康檢查,再發送的請求就不會發送到宕機的服務器了。重新將請求提交到其他的節點上。

使用Nginx的話還能:

節省寬帶:支持GZIP壓縮,可以添加瀏覽器本地緩存

穩定性高:宕機的概率非常小

接收用戶請求是異步的


2. 為什麼Nginx性能這麼高?

因為他的事件處理機制:異步非阻塞事件處理機制:運用了epoll模型,提供了一個隊列,排隊解決

Nginx怎麼處理請求的?

nginx接收一個請求後,首先由listen和server_name指令匹配server模塊,再匹配server模塊裡的location,location就是實際地址

    server                                  # 第一個Server區塊開始,表示一個獨立的虛擬主機站點

        listen       80;                    # 提供服務的端口,默認80

        server_name  localhost;             # 提供服務的域名主機名

        location / {                        # 第一個location區塊開始

            root   html;                    # 站點的根目錄,相當於Nginx的安裝目錄

            index  index.html index.htm;    # 默認的首頁文件,多個用空格分開

        }                                   # 第一個location區塊結果

    }


3. 什麼是正向代理和反向代理?

正向代理就是一個人發送一個請求直接就到達了目標的服務器

反方代理就是請求統一被Nginx接收,nginx反向代理服務器接收到之後,按照一定的規 則分發給了後端的業務處理服務器進行處理了

使用“反向代理服務器的優點是什麼?

反向代理服務器可以隱藏源服務器的存在和特徵。它充當互聯網雲和web服務器之間的中間層。這對於安全方面來說是很好的,特別是當您使用web託管服務時。


4. Nginx的優缺點?

優點:

佔內存小,可實現高並發連接,處理響應快

可實現http服務器、虛擬主機、方向代理、負載均衡

Nginx配置簡單

可以不暴露正式的服務器IP地址

缺點: 動態處理差:nginx處理靜態文件好,耗費內存少,但是處理動態頁面則很雞肋,現在一般前端用nginx作為反向代理抗住壓力,


5. Nginx應用場景?

http服務器。Nginx是一個http服務可以獨立提供http服務。可以做網頁靜態服務器。

虛擬主機。可以實現在一台服務器虛擬出多個網站,例如個人網站使用的虛擬機。

反向代理,負載均衡。當網站的訪問量達到一定程度後,單台服務器不能滿足用戶的請求時,需要用多台服務器集群可以使用nginx做反向代理。並且多台服務器可以平均分擔負載,不會應為某台服務器負載高宕機而某台服務器閒置的情況。

nginz 中也可以配置安全管理、比如可以使用Nginx搭建API接口網關,對每個接口服務進行攔截。


6. 限流怎麼做的?

Nginx限流就是限制用戶請求速度,防止服務器受不了

限流有3種

正常限制訪問頻率(正常流量)

突發限制訪問頻率(突發流量)

限制並發連接數


1、正常限制訪問頻率(正常流量):

限制一個用戶發送的請求,我Nginx多久接收一個請求。

Nginx中使用ngx_http_limit_req_module模塊來限制的訪問頻率,限制的原理實質是基於漏桶算法原理來實現的。在nginx.conf配置文件中可以使用limit_req_zone命令及limit_req命令限制單個IP的請求處理頻率。

    #定義限流維度,一個用戶一分鐘一個請求進來,多餘的全部漏掉

limit_req_zone $binary_remote_addr zone=one:10m rate=1r/m;


#綁定限流維度

server{

location/seckill.html{

limit_req zone=zone;

proxy_pass http://lj_seckill;

}


}

1r/s代表1秒一個請求,1r/m一分鐘接收一個請求, 如果Nginx這時還有別人的請求沒有處理完,Nginx就會拒絕處理該用戶請求。

2、突發限制訪問頻率(突發流量):

限制一個用戶發送的請求,我Nginx多久接收一個。

    #定義限流維度,一個用戶一分鐘一個請求進來,多餘的全部漏掉

limit_req_zone $binary_remote_addr zone=one:10m rate=1r/m;


#綁定限流維度

server{

location/seckill.html{

limit_req zone=zone burst=5 nodelay;

proxy_pass http://lj_seckill;

}


}

上面的配置一定程度可以限制訪問頻率,但是也存在著一個問題:如果突發流量超出請求被拒絕處理,無法處理活動時候的突發流量,這時候應該如何進一步處理呢?Nginx提供burst參數結合nodelay參數可以解決流量突發的問題,可以設置能處理的超過設置的請求數外能額外處理的請求數。我們可以將之前的例子添加burst參數以及nodelay參數:

為什麼就多了一個burst=5 nodelay; 呢,多了這個可以代表Nginx對於一個用戶的請求會立即處理前五個,多餘的就慢慢來落,沒有其他用戶的請求我就處理你的,有其他的請求的話我Nginx就漏掉不接受你的請求

3、 限制並發連接數

Nginx中的ngx_http_limit_conn_module模塊提供了限制並發連接數的功能,可以使用limit_conn_zone指令以及limit_conn執行進行配置。

    http {

        limit_conn_zone $binary_remote_addr zone=myip:10m;

        limit_conn_zone $server_name zone=myServerName:10m;

    }


    server {

        location / {

            limit_conn myip 10;

            limit_conn myServerName 100;

            rewrite / http://www.lijie.net permanent;

        }

    }

面配置了單個IP同時並發連接數最多只能10個連接,並且設置了整個虛擬服務器同時最大並發數最多只能100個鏈接。當然,只有當請求的header被服務器處理後,虛擬服務器的連接數才會計數。剛才有提到過Nginx是基於漏桶算法原理實現的,實際上限流一般都是基於漏桶算法和令牌桶算法實現的。


7. 為什麼要做動靜分離?

Nginx是當下最熱的Web容器,網站優化的重要點在於靜態化網站,網站靜態化的關鍵點則是是動靜分離,動靜分離是讓動態網站裡的動態網頁根據一定規則把不變的資源和經常變的資源區分開來,動靜資源做好了拆分以後,我們則根據靜態資源的特點將其做緩存操作。

讓靜態的資源只走靜態資源服務器,動態的走動態的服務器

Nginx的靜態處理能力很強,但是動態處理能力不足,因此,在企業中常用動靜分離技術。

對於靜態資源比如圖片,js,css等文件,我們則在反向代理服務器nginx中進行緩存。這樣瀏覽器在請求一個靜態資源時,代理服務器nginx就可以直接處理,無需將請求轉發給後端服務器tomcat。若用戶請求的動態文件,比如servlet,jsp則轉發給Tomcat服務器處理,從而實現動靜分離。這也是反向代理服務器的一個重要的作用。

Nginx怎麼做的動靜分離?

只需要指定路徑對應的目錄。location/可以使用正則表達式匹配。並指定對應的硬盤中的目錄。如下:

    location /image/ {

        root   /usr/local/static/;

        autoindex on;

    }

    

8. Nginx負載均衡的算法怎麼實現的?策略有哪些?

為了避免服務器崩潰,大家會通過負載均衡的方式來分擔服務器壓力。將對台服務器組成一個集群,當用戶訪問時,先訪問到一個轉發服務器,再由轉發服務器將訪問分發到壓力更小的服務器。

Nginx負載均衡實現的策略有以下五種:

1 輪詢(默認)

每個請求按時間順序逐一分配到不同的後端服務器,如果後端某個服務器宕機,能自動剔除故障系統。

    upstream backserver { 

        server 192.168.0.12; 

        server 192.168.0.13; 

    } 

2 權重weight

weight的值越大分配

到的訪問概率越高,主要用於後端每台服務器性能不均衡的情況下。其次是為在主從的情況下設置不同的權值,達到合理有效的地利用主機資源。

    upstream backserver { 

        erver 192.168.0.12 weight=2; 

        erver 192.168.0.13 weight=8; 

    } 

權重越高,在被訪問的概率越大,如上例,分別是20%,80%。

3 ip_hash( IP綁定)

每個請求按訪問IP的哈希結果分配,使來自同一個IP的訪客固定訪問一台後端服務器,并且可以有效解决动态网页存在的session共享问题

    upstream backserver { 

        ip_hash; 

        server 192.168.0.12:88; 

        server 192.168.0.13:80; 

    } 

4 fair(第三方插件)

必須安裝upstream_fair模塊。

對比weight、ip_hash更加智能的負載均衡算法,fair算法可以根據頁面大小和加載時間長短智能地進行負載均衡,響應時間短的優先分配。

    upstream backserver { 

        server server1; 

        server server2; 

        fair; 

    } 

哪個服務器的響應速度快,就將請求分配到那個服務器上。

5、url_hash(第三方插件)

必須安裝Nginx的hash軟件包

按訪問url的hash結果來分配請求,使每個url定向到同一個後端服務器,可以進一步提高後端緩存服務器的效率。

    upstream backserver { 

        server squid1:3128; 

        server squid2:3128; 

        hash $request_uri; 

        hash_method crc32; 

    } 

    

9. nginx中500、502、503、504 有什麼區別?

500:Internal Server Error 內部服務錯誤,比如腳本錯誤,編程語言語法錯誤。

502:Bad Gateway錯誤,網關錯誤。比如服務器當前連接太多,響應太慢,頁面素材太多、帶寬慢。

503:Service Temporarily Unavailable,服務不可用,web服務器不能處理HTTP請求,可能是臨時超載或者是服務器進行停機維護。

504:Gateway timeout 網關超時,程序執行時間過長導致響應超時,例如程序需要執行20秒,而nginx最大響應等待時間為10秒,這樣就會出現超時。


10. Nginx服務器上的Master和Worker進程分別是什麼?

Master進程:讀取及評估配置和維持

Worker進程:解決請求


11. 如何用Nginx解決前端跨域問題?

使用Nginx轉發請求。把跨域的接口寫成調本域的接口,然後將這些接口轉發到真正的請求地址。


12. Nginx VS Apache

Apache 通過創建進程和線程來處理其他的連接。管理員可以通過設置來控制服務器所能允許的最大進程數量。這個配置因機器的可用內存而異。過多的進程會耗盡內存從而使得機器使用磁盤上的交換內存,這嚴重的降低了性能。而且,當達到進程的上限之後,Apache 會拒絕新的連接。

Apache可以通過設置來運行在 pre-forked 模式或 worker multi-process 模式 ( MPM )。當其他的用戶連接時,兩種方式都會創建新的進程。區別在於,pre-forked 模式為每一個進程創建一個線程,用來處理一個用戶的請求。worker 模式也創建新的進程,但是每一個進程至少有一個線程,每一個線程用來處理單個用戶的單個請求。所以,一個 worker mode 的進程處理至少一個連接,而一個 per-fork 模式的進程只處理一個連接。

相比於 forked 模式,worker 模式使用更少的內存,原因是進程比線程消耗更多的內存,線程只是運行在進程中的代碼。

此外,worker 模式不是線程安全的。這意味著如果你使用像 mod_php 這樣的非線程安全的模塊來服務 php 頁面時,你需要使用 pre-forked 模式,因此要消耗更多的內存。所以,當選擇模塊和配置服務器時,你必須要面對是線程還是進程更優的問題以及一些約束的問題。

在調整 Apache 時的一個限制因素是內存以及當爭奪同一個 CPU 和內存時潛在的線程死鎖問題。如果一個線程停止了,用戶會一直處於等待頁面出現的狀態,直到進程將該線程回收,以便可以發回頁面。如果一個線程發生了死鎖,它不知道如何重啟,因此會一直處於卡住狀態。

Openresty

和 Apache 相比,Nginx 的工作方式有很大不同,主要是在於它如何處理線程。

Nginx 並不會為每一個的 web 請求創建新的進程,相反,管理員可以配置 Nginx 主進程的工作進程的數量(一個常見的做法是為每一個 CPU 配置一個工作進程)。所有這些進程都是單線程的。每一個工作進程可以處理數千個並發的請求。它通過一個線程來異步的完成了這些工作,而沒有使用多線程的編程模型。

Nginx 還拆分了緩存加載器 ( cache loader ) 和緩存管理器 ( cache manager ) 進程用來從磁盤中讀取數據並將其加載到緩存中,當緩存直接讀取的時候緩存過期。

Nginx 有一系列的模塊組成,這些模塊在編譯的時候就被包含進去了。這意味著,用戶下載源碼並選擇他們要編譯的模塊。這些模塊中包括連接後端應用服務器,負載均衡,代理服務器以及其他。並沒有 PHP 的模塊,因為 Nginx 可以自己編譯 PHP 代碼。

2022年3月4日 星期五

《面試官別再問》PHP 面試整理

1. 列舉一些PHP 中的設計模式?

    單例模式:保證在整個應用程序的生命週期中,任何一個時刻,單例類的實例都只存在一個,同時這個類還必須提供一個訪問該類的全局訪問點。

    工廠模式:定義一個創建物件的接口,但是讓子類去實例化具體類。工廠方法模式讓類的實例化延遲到子類中。

    觀察者模式:觀察者模式有時也被稱作發布/訂閱模式,該模式用於為物件實現發布/訂閱功能:一旦主體物件狀態發生改變,與之關聯的觀察者物件會收到通知,並進行相應操作。

    適配器模式:適配器模式將一個類的接口轉換成客戶希望的另外一個接口,使得原本由於接口不兼容而不能一起工作的那些類可以在一起工作。

    依賴注入模式:依賴注入(DependencyInjection)是控制反轉(Inversion ofControl)的一種實現方式。要實現控制反轉,通常的解決方案是將創建被調用者實例的工作交由IoC 容器來完成,然後在調用者中註入被調用者(通過構造器/方法注入實現),這樣我們就實現了調用者與被調用者的解耦,該過程被稱為依賴注入。

    門面模式:門面模式(Facade)又稱外觀模式,用於為子系統中的一組接口提供一個一致的界面。


2. Session可不可以設置失效時間,比如30分鐘過期

    設置seesion.cookie_lifetime有30分鐘,並設置session.gc_maxlifetime為30分鐘

    自己為每一個Session值增加timestamp

    每次訪問之前, 判斷時間戳


3. 類的靜態調用和實例化調用各自的利弊

    靜態方法是類中的一個成員方法,屬於整個類,即使不用創建任何對像也可以直接調用!靜態方法效率上要比實例化高,靜態方法的缺點是不自動銷毀,而實例化的則可以做銷毀。


4. Redis五種資料類型及應用場景

    String: 一般做一些複雜的計數功能的緩存

    List: 做簡單的消息隊列的功能

    Hash: 單點登錄

    Set: 做全局去重的功能

    SortedSet: 做排行榜應用,取TopN操作;延時任務;做範圍查找


    Redis string 是redis 最基本的類型,你可以理解成與Memcached 一模一樣的類型,一個key 對應一個value。value其實不僅是String,也可以是數字。string 類型是二進制安全的。

    意思是redis 的string 可以包含任何資料。比如jpg圖片或者序列化的物件。string 類型是Redis 最基本的資料類型,string 類型的值最大能存儲512MB。

    常用命令:get、set、incr、decr、mget等。

    應用場景: String是最常用的一種資料類型,普通的key/ value 存儲都可以歸為此類,即可以完全實現目前Memcached 的功能,並且效率更高。還可以享受Redis的定時持久化,操作日誌及Replication等功能。

    Redis hash 是一個鍵值(key => value)對集合。Redis hash 是一個string 類型的field 和value 的映射表,hash 特別適合用於存儲物件。

    常用命令:hget,hset,hgetall 等。

    應用場景:我們簡單舉個實例來描述下Hash的應用場景,比如我們要存儲一個用戶信息對像資料,包含以下信息:

    用戶ID為查找的key,存儲的value用戶物件包含姓名,年齡,生日等信息。

    使用場景:存儲部分變更資料,如用戶信息等。

    Redis list 列表是簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)。

    常用命令:lpush(添加左邊元素),rpush,lpop(移除左邊第一個元素),rpop,lrange(獲取列表片段,LRANGE key start stop)等。

    應用場景:Redis list的應用場景非常多,也是Redis最重要的資料結構之一,比如twitter的關注列表,粉絲列表等都可以用Redis的list結構來實現。

    Redis set是string類型的無序集合。集合是通過hashtable實現的,概念和數學中個的集合基本類似,可以交集,並集,差集等等,set中的元素是沒有順序的。所以添加,刪除,查找的複雜度都是O(1)。

    sadd 命令:添加一個string 元素到key 對應的set 集合中,成功返回1,如果元素已經在集合中返回0,如果key 對應的set 不存在則返回錯誤。

    常用命令:sadd,spop,smembers,sunion 等。

    應用場景:Redis set對外提供的功能與list類似是一個列表的功能,特殊之處在於set是可以自動排重的,當你需要存儲一個列表資料,又不希望出現重複資料時,set是一個很好的選擇,並且set提供了判斷某個成員是否在一個set集合內的重要接口,這個也是list所不能提供的。

    Set 就是一個集合,集合的概念就是一堆不重複值的組合。利用Redis提供的Set資料結構,可以存儲一些集合性的資料。

    Redis zset 和set 一樣也是string類型元素的集合,且不允許重複的成員。

    zadd 命令:添加元素到集合,元素在集合中存在則更新對應score。

    常用命令:zadd,zrange,zrem,zcard等

    使用場景:Redis sorted set的使用場景與set類似,區別是set不是自動有序的,而sorted set可以通過用戶額外提供一個優先級(score)的參數來為成員排序,並且是插入有序的,即自動排序。

    當你需要一個有序的並且不重複的集合列表,那麼可以選擇sorted set資料結構,比如twitter 的public timeline可以以發表時間作為score來存儲,這樣獲取時就是自動按時間排好序的。和Set相比,Sorted Set關聯了一個double類型權重參數score,使得集合中的元素能夠按score進行有序排列,redis正是通過分數來為集合中的成員進行從小到大的排序。

    zset的成員是唯一的,但分數(score)卻可以重複。比如一個存儲全班同學成績的Sorted Set,其集合value可以是同學的學號,而score就可以是其考試得分,這樣在資料插入集合的時候,就已經進行了天然的排序。另外還可以用Sorted Set來做帶權重的隊列,比如普通消息的score為1,重要消息的score為2,然後工作線程可以選擇按score的倒序來獲取工作任務。讓重要的任務優先執行。


5. Redis 緩存雪崩、擊穿、穿透

    什麼是緩存雪崩?

    當某一個時刻出現大規模的緩存失效的情況,那麼就會導致大量的請求直接打在資料庫上面,導致資料庫壓力巨大,如果在高並發的情況下,可能瞬間就會導致資料庫宕機。這時候如果運維馬上又重啟資料庫,馬上又會有新的流量把資料庫打死。這就是緩存雪崩。

    解決方案:

    1、在原有的失效時間上加上一個隨機值,比如1-5分鐘隨機。這樣就避免了因為採用相同的過期時間導致的緩存雪崩。

    2、使用熔斷機制。當流量到達一定的閾值時,就直接返回“系統擁擠”之類的提示,防止過多的請求打在數據庫上。至少能保證一部分用戶是可以正常使用,其他用戶多刷新幾次也能得到結果。

    3、提高數據庫的容災能力,可以使用分庫分錶,讀寫分離的策略。

    什麼是緩存擊穿?

    其實跟緩存雪崩有點類似,緩存雪崩是大規模的key失效,而緩存擊穿是一個熱點的Key,有大並發集中對其進行訪問,突然間這個Key失效了,導致大並發全部打在數據庫上,導致數據庫壓力劇增。這種現象就叫做緩存擊穿。

    解決方案:

    1、上面說過了,如果業務允許的話,對於熱點的key可以設置永不過期的key。

    2、使用互斥鎖。如果緩存失效的情況,只有拿到鎖才可以查詢數據庫,降低了在同一時刻打在數據庫上的請求,防止數據庫打死。當然這樣會導致系統的性能變差。

    什麼是緩存穿透?

    使用Redis大部分情況都是通過Key查詢對應的值,假如發送的請求傳進來的key是不存在Redis中的,那麼就查不到緩存,查不到緩存就會去數據庫查詢。假如有大量這樣的請求,這些請求像“穿透”了緩存一樣直接打在數據庫上,這種現象就叫做緩存穿透。

    解決方案:

    1、把無效的Key存進Redis中。如果Redis查不到數據,數據庫也查不到,我們把這個Key值保存進Redis,設置value="null",當下次再通過這個Key查詢時就不需要再查詢數據庫。這種處理方式肯定是有問題的,假如傳進來的這個不存在的Key值每次都是隨機的,那存進Redis也沒有意義。

    2、使用布隆過濾器。布隆過濾器的作用是某個key 不存在,那麼就一定不存在,它說某個key 存在,那麼很大可能是存在(存在一定的誤判率)。於是我們可以在緩存之前再加一層布隆過濾器,在查詢的時候先去布隆過濾器查詢key 是否存在,如果不存在就直接返回。


6. php7新特性

    1.可以使用字符串(string), 整數(int), 浮點數(float), 以及布爾值(bool),來聲明函數的參數類型與函數返回值

    2.新增操作符“<=>” 語法:$c = $a <=> $b 

    如果$a > $b, $c 的值為1

    如果$a == $b, $c 的值為0

    如果$a < $b, $c 的值為-1

    3.新增操作符“??” 如果變數存在且值不為NULL, 它就會返回自身的值,否則返回它的第二個操作數。

    //原寫法

    $username = isset($_GET['user]) ? $_GET['user] : 'nobody';

    //新寫法

    $username = $_GET['user'] ?? 'nobody';

    4.define() 定義常量陣列

    define('ARR',['a','b']);

    echo ARR[1];// a

    5.命名空間引用優化

    // PHP7以前语法的写法

    use FooLibrary\Bar\Baz\ClassA;

    use FooLibrary\Bar\Baz\ClassB;

    // PHP7新语法写法

    use FooLibrary\Bar\Baz\{ ClassA, ClassB};

    6.list修改

    不再按照相反的順序賦值

    //$arr将会是[1,2,3]而不是之前的[3,2,1]

    list($arr[], $arr[], $arr[]) = [1,2,3];

    不再支持字符串拆分功能

    // $x = null 并且 $y = null

    $str = 'xy';

    list($x, $y) = $str;

    空的list()賦值不再允許

    list() = [123];

    list()現在也適用於陣列物件

    list($a, $b) = (object)new ArrayObject([0, 1]);


7. 如何設計/優化一個訪問量比較大的部落格/論壇

    減少http請求(比如使用雪碧圖)

    優化數據庫(範式、SQL語句、索引、配置、讀寫分離)

    緩存使用(Memcache、Redis)

    負載均衡

    動態內容靜態化+CDN

    禁止外部盜鏈(refer、圖片添加水印)

    控制大文件下載

    使用集群

    

8. PHP使用Nginx實現反向代理

    1、什麼是代理伺服器

    代理伺服器,客戶機在發送請求時,不會直接發送給目的主機,而是先發送給代理伺服器,代理服務接受客戶機請求之後,再向主機發出,並接收目的主機返回的數據,存放在代理伺服器的硬盤中,再發送給客戶機。

    2、為什麼要使用代理伺服器

    1)提高訪問速度

    由於目標主機返回的數據會存放在代理伺服器的硬盤中,因此下一次客戶再訪問相同的站點數據時,會直接從代理伺服器的硬盤中讀取,起到了緩存的作用,尤其對於熱門站點能明顯提高請求速度。

    2)防火牆作用

    由於所有的客戶機請求都必須通過代理伺服器訪問遠程站點,因此可在代理伺服器上設限,過濾某些不安全信息。

    3)通過代理伺服器訪問不能訪問的目標站點

    互聯網上有許多開發的代理伺服器,客戶機在訪問受限時,可通過不受限的代理伺服器訪問目標站點,通俗說,我們使用的翻牆瀏覽器就是利用了代理伺服器,雖然不能出國,但也可直接訪問外網。

    二、反向代理VS 正向代理

    1、什麼是正向代理?什麼是反向代理?

    正向代理,架設在客戶機與目標主機之間,只用於代理內部網絡對Internet的連接請求,客戶機必須指定代理伺服器,並將本來要直接發送到Web伺服器上的http請求發送到代理伺服器中。

    反向代理伺服器架設在伺服器端,通過緩衝經常被請求的頁面來緩解伺服器的工作量,將客戶機請求轉發給內部網絡上的目標伺服器;並將從伺服器上得到的結果返回給Internet上請求連接的客戶端,此時代理伺服器與目標主機一起對外表現為一個伺服器。

    2、反向代理有哪些主要應用?

    現在許多大型web網站都用到反向代理。除了可以防止外網對內網伺服器的惡性攻擊、緩存以減少伺服器的壓力和訪問安全控制之外,還可以進行負載均衡,將用戶請求分配給多個伺服器。


9. php構建api上的CORS問題

    跨域資源共享 CORS (Cross-origin resource sharing) 是一個 W3C 標準

    這裡是常見的設定方式:

    <?php

      header("Access-Control-Allow-Origin: *");

      header("Access-Control-Allow-Methods: *");

      header("Access-Control-Allow-Headers: Origin, Methods, Content-Type");

《面試官別再問》MySQL面試題總結

1. 什麼是MVCC

MVCC,Multi-Version Concurrency Control,多版本併發控制。MVCC 是一種併發控制的方法,一般在資料庫管理系統中,實現對資料庫的併發訪問;在程式語言中實現事務記憶體。

簡單來說,多版本並發控制 的思想就是保存資料的歷史版本,通過對資料行的多個版本管理來實現資料庫的並發控制。這樣我們就可以通過比較版本號決定資料是否顯示出來,讀取資料的時候不需要加鎖也可以保證事務的隔離效果。

可以認為 多版本並發控制(MVCC)是行級鎖的一個變種,但是它在很多情況下避免了加鎖操作,因此開銷更低。雖然實現機制有所不同,但大都實現了非阻塞的讀操作,寫操作也只鎖定必要的??。

MySQL的大多數事務型存儲引擎實現的都不是簡單的行級鎖。基於提升並發性能的考慮,它們一般都同時實現了多版本並發控制(MVCC)。不僅是MySQL,包括Oracle、PostgreSQL等其他資料庫系統也都實現了MVCC,但各自的實現機制不盡相同,因為MVCC沒有一個統一的實現標準,典型的有樂觀(optimistic)並發控制和悲觀(pessimistic)並發控制。

多版本並發控制(MVCC)在一定程度上實現了讀寫並發,它只在 可重複讀(REPEATABLE READ)和 提交讀(READ COMMITTED)兩個隔離級別下工作。其他兩個隔離級別都和MVCC 不兼容,因為 未提交讀(READ UNCOMMITTED),總是讀取最新的資料行,而不是符合當前事務版本的資料行。而 可串行化(SERIALIZABLE)則會對所有讀取的行都加鎖。


2. MySQL的邏輯架構

連接層

主要工作是:連接處理、授權認證、安全防護等。

服務層(server層)

服務層用於處理核心服務,如標準的SQL接口、查詢解析、SQL優化和統計、全局的和引擎依賴的緩存與緩衝器等等。所有的與存儲引擎無關的工作,如過程、函數等,都會在這一層來處理。在該層上,服務器會解析查詢並創建相應的內部解析樹,並對其完成優化,如確定查詢表的順序,是否利用索引等,最後生成相關的執行操作。如果是SELECT 語句,服務器還會查詢內部的緩存。如果緩存空間足夠大,這樣在解決大量讀操作的環境中能夠很好的提升系統的性能。

分析器

如果沒有命中緩存,就開始做詞法分析和語法分析

詞法分析:MySQL 從你輸入的"select"這個關鍵字識別出來,這是一個查詢語句。它也要把字符串“T”識別成“表名T”,把字符串“ID”識別成“列ID”

語法分析:判斷你輸入的這個SQL 語句是否滿足MySQL 語法。如果語句不對,就會收到“You have an error in your SQL syntax”的錯誤提醒

優化器

優化器是在表裡面有多個索引的時候,決定使用哪個索引;或者在一個語句有多表關聯(join)的時候,決定各個表的連接順序

執行器

開始執行的時候,要先判斷一下對這個表T 有沒有執行查詢的權限,如果沒有,就會返回沒有權限的錯誤(在工程實現上,如果命中查詢緩存,會在查詢緩存返回結果的時候,做權限驗證。查詢也會在優化器之前調用precheck 驗證權限)。如果有權限,就打開表繼續執行。打開表的時候,執行器就會根據表的引擎定義,去使用這個引擎提供的接口。


3. MySQL的讀寫鎖?

表鎖:不會出現死鎖,發生鎖衝突機率高,併發低

行鎖:會出現死鎖,發生鎖衝突機率低,併發高

鎖衝突:例如說事務A將某幾行上鎖後,事務B又對其上鎖,鎖不能共存否則會出現鎖衝突。(但是共享鎖可以共存,共享鎖和排它鎖不能共存,排它鎖和排他鎖也不可以)

死鎖:例如說兩個事務,事務A鎖住了1~5行,同時事務B鎖住了6~10行,此時事務A請求鎖住6~10行,就會阻塞直到事務B施放6~10行的鎖,而隨後事務B又請求鎖住1~5行,事務B也阻塞直到事務A釋放1~5行的鎖。死鎖發生時,會產生Deadlock錯誤。鎖是對錶操作的,所以自然鎖住全表的表鎖就不會出現死鎖。

行鎖的型別

共享鎖又稱:讀鎖。當一個事務對某幾行上讀鎖時,允許其他事務對這幾行進行讀操作,但不允許其進行寫操作,也不允許其他事務給這幾行上排它鎖,但允許上讀鎖。

排它鎖又稱:寫鎖。當一個事務對某幾個上寫鎖時,不允許其他事務寫,但允許讀。更不允許其他事務給這幾行上任何鎖。包括寫鎖。

共享鎖的寫法:lock in share mode

select  * from  test where math>60 lock in share mode;

排它鎖的寫法:for update

select * from test where math >60 for update;

行鎖的實現 注意幾點

1.行鎖必須有索引才能實現,否則會自動鎖全表

2.兩個事務不能鎖同一個索引


客戶端A讀取操作不需要等待客戶端B讀取完成並釋放鎖。但客戶端A進行寫操作的時候,會阻塞其他客戶端的讀和寫操作,直到客戶端A寫操作完成並釋放鎖,其他客戶端才可以進行讀寫。

上面說了這麼多,但實際上當客戶端A更新某行記錄的同時,客戶端B任然可讀取到資料,不會被阻塞,這是為什麼呢?

先來了解兩個東西,Redo Log(重做日誌)和Undo Log(回滾日誌)

redo log通常是物理日誌,記錄的是資料頁的物理修改,它用來恢復提交後的物理資料頁(恢復資料頁,且只能恢復到最後一次提交的位置)。

undo用來回滾行記錄到某個版本。undo log一般是邏輯日誌,根據每行記錄進行記錄。

如果看不懂,就這樣理解:當發生寫操作時,Innodb會把舊資料存儲到Undo Log(回滾日誌)中,新資料寫到Redo Log(重做日誌)中。

當客戶端A更新某行記錄的同時,客戶端B會被寫鎖阻塞,這時,客戶端B會去Undo Log中讀取舊資料。


4. 怎麼解決MySQL死鎖問題?

從死鎖的定義來看,MySQL 出現死鎖的幾個要素為:

兩個或者兩個以上事務

每個事務都已經持有鎖並且申請新的鎖

鎖資源同時只能被同一個事務持有或者不兼容

事務之間因為持有鎖和申請鎖導致彼此循環等待


一個用戶A 訪問表A(鎖住了表A),然後又訪問表B;另一個用戶B 訪問表B(鎖住了表B),然後企圖訪問表A;這時用戶A由於用戶B已經鎖住表B,它必須等待用戶B釋放表B才能繼續,同樣用戶B要等用戶A釋放表A才能繼續,這就死鎖就產生了。

解決方法

這種死鎖比較常見,是由於程序的BUG產生的,除了調整程序的邏輯沒有其它的辦法。仔細分析程序的邏輯,對於資料庫的多表操作時,盡量按照相同的順序進行處理,盡量避免同時鎖定兩個資源,如操作A和B兩張表時,總是按先A後B的順序處理, 必須同時鎖定兩個資源時,要保證在任何時刻都應該按照相同的順序來鎖定資源。


如果在事務中執行了一條不滿足條件的update語句,則執行全表掃描,把行級鎖上升為表級鎖,多個這樣的事務執行後,就很容易產生死鎖和阻塞。類似的情況還有當表中的資料量非常龐大而索引建的過少或不合適的時候,使得經常發生全表掃描,最終應用系統會越來越慢,最終發生阻塞或死鎖。

解決方法

SQL語句中不要使用太複雜的關聯多表的查詢;使用“執行計劃”對SQL語句進行分析,對於有全表掃描的SQL語句,建立相應的索引進行優化。


5. InnoDB四大特性

插入緩存(insert buffer)

對非聚集索引的插入或者update,purge等操作,並非每一次直接插入索引頁,而是把若干對於同一頁面的更新緩存起來合併為一次操作,隨機IO –> 順序IO,避免隨機IO帶的性能消耗,提高寫性能。

二次寫(double write)

帶給innodb存儲引擎資料的可靠性

起因:當資料庫宕機時,可能發生資料庫寫一個頁面,而這個頁只寫了一部分,這就是所謂的部分寫失效(partial page write),它會導致資料丟失,這時是無法通過重做日誌恢復的,因為重做日誌記錄的是對頁的物理修改,如果頁本身已經損壞,重做日誌也無能為力。

恢復原理:mysql在恢復的時候是通過檢查page的checksum來決定這個頁是否需要恢復,checksum就是當前這個頁最後一個事務的事務號,如果系統找不到checksum,mysql就無法對該行資料進行寫入操作

自適應哈希索引(adapter hash index)

innodb存儲引擎會監控對錶上索引的查找,如果觀察到建立哈希索引可以帶來速度上的提升,則建立哈希索引,所以稱為自適應的。

自適應哈希索引通過緩衝池的B+樹構造而來,因為建立的速度很快,而且不需要將整個表都建立哈希索引,innodb會自動根據訪問頻率和模式來為某些頁建立哈希索引。

啟用自適應哈希索引後,讀寫速度提高兩倍,輔助索引的鏈接操作,性能提高五倍。

可以通過show engine innodb status\G來查看自適應哈西索引的使用情況。可以使用innodb_adaptive_hash_index來禁用和啟用hash索引,默認開啟。


6. MySQL事務隔離級別和實現原理

事務具有原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)四個特性,簡稱ACID,缺一不可。

臟讀指的是讀到了其他事務未提交的資料,未提交意味著這些資料可能會回滾,也就是可能最終不會存到資料庫中,也就是不存在的資料。讀到了並一定最終存在的資料,這就是臟讀。

可重複讀指的是在一個事務內,最開始讀到的資料和事務結束前的任意時刻讀到的同一批資料都是一致的。通常針對資料更新(UPDATE)操作。

對比可重複讀,不可重複讀指的是在同一事務內,不同的時刻讀到的同一批資料可能是不一樣的,可能會受到其他事務的影響,比如其他事務改了這批資料並提交了。通常針對資料更新(UPDATE)操作。

幻讀是針對資料插入(INSERT)操作來說的。假設事務A對某些行的內容作了更改,但是還未提交,此時事務B插入了與事務A更改前的記錄相同的記錄行,並且在事務A提交之前先提交了,而這時,在事務A中查詢,會發現好像剛剛的更改對於某些資料未起作用,但其實是事務B剛插入進來的,讓用戶感覺很魔幻,感覺出現了幻覺,這就叫幻讀。

SQL 標准定義了四種隔離級別,MySQL 全都支持。這四種隔離級別分別是:

讀未提交(READ UNCOMMITTED)

讀提交(READ COMMITTED)

可重複讀(REPEATABLE READ)

串行化(SERIALIZABLE)

從上往下,隔離強度逐漸增強,性能逐漸變差。採用哪種隔離級別要根據系統需求權衡決定,其中,可重複讀是MySQL 的默認級別。

事務隔離其實就是為了解決上面提到的髒讀、不可重複讀、幻讀這幾個問題,下面展示了4 種隔離級別對這三個問題的解決程度。


7. 什麼是全文索引?

MySQL 從 5.7.6 版本開始,MySQL就內建了ngram全文解析器,用來支援中文、日文、韓文分詞。在 MySQL 5.7.6 版本之前,全文索引只支援英文全文索引,不支援中文全文索引,需要利用分詞器把中文段落預處理拆分成單詞,然後存入資料庫。

ngram就是一段文字裡面連續的n個字的序列。ngram全文解析器能夠對文字進行分詞,每個單詞是連續的n個字的序列。

MySQL 中使用全域性變數ngram_token_size來配置ngram中n的大小,它的取值範圍是1到10,預設值是2。通常ngram_token_size設定為要查詢的單詞的最小字數。如果需要搜尋單字,就要把ngram_token_size設定為1。在預設值是2的情況下,搜尋單字是得不到任何結果的。因為中文單詞最少是兩個漢字,推薦使用預設值2。

常用的全文檢索模式有兩種:

1、自然語言模式(NATURAL LANGUAGE MODE) ,

自然語言模式是MySQL 預設的全文檢索模式。自然語言模式不能使用操作符,不能指定關鍵詞必須出現或者必須不能出現等複雜查詢。

2、BOOLEAN模式(BOOLEAN MODE)

BOOLEAN模式可以使用操作符,可以支援指定關鍵詞必須出現或者必須不能出現或者關鍵詞的權重高還是低等複雜查詢。


8. 什麼是覆蓋索引?

覆蓋索引的定義有如下三種:

解釋一:就是select的資料列只用從索引中就能夠取得,不必從資料表中讀取,換句話說查詢列要被所使用的索引覆蓋。

解釋二:索引是高效找到行的一個方法,當能通過檢索索引就可以讀取想要的資料,那就不需要再到資料表中讀取行了。如果一個索引包含了(或覆蓋了)滿足查詢語句中欄位與條件的資料就叫做覆蓋索引。

解釋三:是非聚集組合索引的一種形式,它包括在查詢里的Select、Join和Where子句用到的所有列(即建立索引的欄位正好是覆蓋查詢語句[select子句]與查詢條件[Where子句]中所涉及的欄位,也即,索引包含了查詢正在查找的所有資料)。

通俗些說,覆蓋索引就是能在某次查詢中能同時覆蓋到所有的查詢結果和查詢條件的索引。這裡強調兩點:覆蓋索引首先是一個索引;覆蓋索引覆蓋的是什麼呢?覆蓋的是所有查要讀取的所有的列,同時也覆蓋所有的查詢條件。

索引條目通常遠小於資料行大小,所以如果只需讀取索引,那mysql就會極大的減少資料訪問量。這對緩存的負載非常重要,因為這種情況下響應時間大部分花費在資料拷貝上。覆蓋索引對於I/O密集型的應用也很有幫助,因為索引比資料更小,更容易全部放入內存中。

由於InnoDB的聚簇索引,覆蓋索引對InnoDB特別有用。InnoDB的二級索引在葉子節點中保存了行的主鍵值,所以如果二級主鍵能夠覆蓋查詢,則可以避免對主鍵索引的二次查詢。減少IO,提高效率。


9. 索引失效的情況有哪些?

一、單表查詢時索引失效

1、mysql查詢單表時,查詢得到的結果集佔資料總量很大比例,mysql會認為全表掃描會優於索引,則不走索引。

例:比如企業人員信息表 (userInfo),字段(user_id、user_name、user_type(vachar)),假設企業裡有10w人,一千個管理層user_type為1,9萬9千人為普通員工user_type為2,

sql:select * from userInfo where user_type='2' 這時user_type字段索引可能會失效

2、查詢時where條件後的字段類型要與表結構中該字段類型一致,

例:select * from userInfo where user_type=2 ,user_type在表結構中時字符類型,查詢時沒用有單引號包含起來則不走索引。

3、在where條件後對索引字段加了函數轉換或者運算邏輯(+、-、*、/、!、<>、%、like'%_'(%放在前面)、or、in (疑問、可能存在成本問題)、exist等)的處理,比如對時間戳字段進行日期格式化函數都會引起索引失效。

二、多表關聯查詢時索引失效

1、在表結構設計階段主表與關聯表之間的關聯字段的資料類型、資料長度、字段的編碼格式以及字段的排序規則需要保持一致

三、組合索引

1、當一張表的查詢方式比較固定,這時候可以嘗試創建聚集索引,查詢時應當遵從組合索引的規則,最左原則,查詢時使用最頻繁的一列放在最左邊,

例:index(user_id,user_name,user_type)這是一個組合索引,當查詢時如果想走索引則

sql:select * from userInfo where user_id='001' and user_name='小張' and user_type='1';這個時候是走了索引的,但是

select * from userInfo where  user_name='小張' and user_type='1';這時user_id沒有在where條件內將不走索引;

此例,user_id字段必須出現在where後面,不然索引將不會生效。


10. Trace 是做什麼用的?

# 1. 開啟optimizer trace功能 (預設情況下它是關閉的):

SET optimizer_trace="enabled=on";

SELECT ...; # 這裡輸入你自己的查詢語句

SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;

# 當你停止檢視語句的優化過程時,把optimizer trace功能關閉

SET optimizer_trace="enabled=off";

QUERY:表示我們的查詢語句。

TRACE:表示優化過程的JSON格式文字。

MISSING_BYTES_BEYOND_MAX_MEM_SIZE:由於優化過程可能會輸出很多,如果超過某個限制時,多餘的文字將不會被顯示,這個欄位展示了被忽略的文字位元組數。

INSUFFICIENT_PRIVILEGES:表示是否沒有許可權檢視優化過程,預設值是0,只有某些特殊情況下才會是1,我們暫時不關心這個欄位的值。


11. 什麼是mysql主從同步?

當master(主)庫的資料發生變化的時候,變化會實時的同步到slave(從)庫。

資料是一個應用至關重要的一部分。從目的出發,主從同步有那麼點備份的意思,主庫(Master)將自己庫中的寫入同時同步給自己的從庫(Slave),當主庫發生某些不可預知的狀況,導致整個伺服器無法使用時,由於從庫中也有一份資料,所以資料可以做到快速恢復,不造成或者減少造成資料的損失。

當我們在MySQL中設定了主從之後,只要我們對Master節點進行了寫操作,這個操作將會被儲存到MySQL的binary-log(bin-log)紀錄檔當中,當slave連線到master的時候,master機器會為slave開啟binlog dump執行緒。當master 的 binlog發生變化的時候,Master的dump執行緒會通知slave,並將相應的binlog內容傳送給Slave。而Slave節點在主從同步開啟的時候,會建立兩個執行緒,一個I/O執行緒,一個SQL執行緒,這在我們後面的搭建中可以親眼看到。

I/0執行緒:該執行緒連結到master機器,master機器的binlog傳送到slave的時候,IO執行緒會將該紀錄檔內容寫在原生的中繼紀錄檔(Relay log)中。

SQL執行緒:該執行緒讀取中繼紀錄檔中的內容,並且根據中繼紀錄檔中的內容對Slave資料庫做相應的操作。

可能造成的問題:在寫請求相當多的情況下,可能會造成Slave資料和Master資料不一致的情況,這是因為紀錄檔傳輸過程中的短暫延遲、或者寫命令較多,系統速度不匹配造成的。


12. Join的使用技巧和優化

join用於多表中欄位之間的聯繫,在資料庫的DML (資料操作語言,即各種增刪改查操作)中有著重要的作用。

合理使用Join語句優化SQL有利於:

增加資料庫的處理效率,減少響應時間;

減少資料庫伺服器負載,增加伺服器穩定性;

減少伺服器通訊的網絡流量;

1. Join的分類:

內連接 Inner Join

全外連接 FULL Outer Join

左外連接 Left Outer Join

右外連接 Right Outer Join

交叉連接 Cross Join

MySQL按如下方式實現A LEFT JOIN B:

表B被設置為依賴於表A和A所依賴的所有表。 表A被設置為依賴於在LEFT JOIN條件中使用的所有表(除了B)。 LEFT JOIN條件用於決定如何從表B中檢索行(換句話說,不使用WHERE子句中的任何條件)。 所有標準連接優化都執行,不同之處在於一個表總是在它所依賴的所有表之後被讀取。 如果有循環依賴,則會發生錯誤。 所有標準的WHERE優化都被執行。 如果A中存在與WHERE子句匹配的行,但B中沒有與ON條件相匹配的行,則會生成一個額外的B行,並將所有列設置為NULL。 如果使用LEFT JOIN查找某些表中不存在的行,並且您有以下測試:在WHERE部分中,col_name是NULL,其中col_name是一個聲明為NOT NULL的列,MySQL將停止搜尋更多行(為瞭找到一行符合LEFT JOIN條件的特定組合鍵)。

RIGHT JOIN實現類似於LEFT JOIN,其表格角色顛倒瞭。 右連接轉換為等效的左連接

連接優化器計算連接表的順序。 由LEFT JOIN或STRAIGHT_JOIN強制的表讀順序可以幫助聯接優化器更快地完成工作,因為檢查的表排列更少。 這意味著如果執行以下類型的查詢,MySQL會對b執行完整掃描,因為LEFT JOIN強制在d之前讀取它:

那麼如何優化LEFT JOIN:  

1、條件中盡量能夠過濾一些行將驅動表變得小一點,用小表去驅動大表 

2、右表的條件列一定要加上索引(主鍵、唯一索引、前綴索引等),最好能夠使type達到range及以上(ref,eq_ref,const,system)  


13. 資料庫為什麼使用B+樹而不是B樹

1、B樹只適合隨機檢索,而B+樹同時支持隨機檢索和順序檢索;

2、B+樹空間利用率更高,可減少I/O次數,磁盤讀寫代價更低。一般來說,索引本身也很大,不可能全部存儲在內存中,因此索引往往以索引文件的形式存儲的磁盤上。這樣的話,索引查找過程中就要產生磁盤I/O消耗。B+樹的內部結點並沒有指向關鍵字具體信息的指針,只是作為索引使用,其內部結點比B樹小,盤塊能容納的結點中關鍵字數量更多,一次性讀入內存中可以查找的關鍵字也就越多,相對的,IO讀寫次數也就降低了。而IO讀寫次數是影響索引檢索效率的最大因素;

3、B+樹的查詢效率更加穩定。B樹搜索有可能會在非葉子結點結束,越靠近根節點的記錄查找時間越短,只要找到關鍵字即可確定記錄的存在,其性能等價於在關鍵字全集內做一次二分查找。而在B+樹中,順序檢索比較明顯,隨機檢索時,任何關鍵字的查找都必須走一條從根節點到葉節點的路,所有關鍵字的查找路徑長度相同,導致每一個關鍵字的查詢效率相當。

4、B-樹在提高了磁盤IO性能的同時並沒有解決元素遍歷的效率低下的問題。B+樹的葉子節點使用指針順序連接在一起,只要遍歷葉子節點就可以實現整棵樹的遍歷。而且在資料庫中基於範圍的查詢是非常頻繁的,而B樹不支持這樣的操作。

5、增刪文件(節點)時,效率更高。因為B+樹的葉子節點包含所有關鍵字,並以有序的鍊錶結構存儲,這樣可很好提高增刪效率。


14. In與Exists的區別 

EXISTS操作符用來判斷一個子查詢是否返回數據行。如果一個子查詢返回了至少一個數據行,則 EXISTS 的計算結果為TRUE,否則計算結果為FALSE。

not exists與exists相反,也就是當exists條件有結果集返回時,loop到的記錄將被丟棄,否則將loop到的記錄加入結果集

EXISTS運算的結果只與子查詢是否返回數據行有關,子查詢中的列的數量或者名稱不影響運算結果。

總的來說,in查詢就是先將子查詢條件的記錄全都查出來,假設結果集為B,共有m條記錄,然後在將子查詢條件的結果集分解成m個,再進行m次查詢


15 該如何防止sql注入?我們通過以下三種方法進行防治sql注入

1.開啟php的魔術模式,,magic_quotes_gpc = on即可,當一些特殊字符出現在網站前端的時候,就會自動進行轉化,轉化成一些其他符號導致sql語句無法執行。

2.網站代碼裡寫入過濾sql特殊字符的代碼,對一些特殊字符進行轉化,比如單引號,逗號,*,(括號)AND 1=1 、反斜槓,select union等查詢的sql語句都進行安全過濾,限制這些字符的輸入,禁止提交到後端中去。

3.開啟網站防火牆,IIS防火牆,apache防火牆,nginx防火牆,都有內置的過濾sql注入的參數,當用戶輸入參數get、post、cookies方式提交過來的都會提前檢測攔截。

《面試官別再問》mysql查詢優化器提示(hint)

mysql提供了另一種神奇的功能讓我們去引導優化器進行更好的優化。

它就是 查詢優化提示(Query Optimizer Hints);

查詢優化提示會提示優化器按照一定的方式去優化,讓你的sql語句更具靈活性,這會讓你的查詢更快,當然也可能更慢,這完全取決於你對優化器的理解和場景的了解。

現在讓我們來了解有哪些查詢優化提示:


優先操作HIGH_PRIORITY

HIGH_PRIORITY可以使用在select和insert操作中,讓MYSQL知道,這個操作優先進行。

SELECT HIGH_PRIORITY * FROM TABLE1;

滯後操作LOW_PRIORITY

LOW_PRIORITY可以使用在select,delete,insert和update操作中,讓mysql知道,這個操作滯後。

update LOW_PRIORITY table1 set field1= where field1= …

這兩個提示都只在基於表鎖的存儲引擎非常有效。在innoDB和其他基於行鎖的存儲引擎,你可能永遠用不上。在MyISAM中使用它們時,也要十分小心,因為它們會讓並發插入失效,可能會嚴重下降性能。


延時插入DELAYED

這個操作只能用於insert 和replace

INSERT DELAYED INTO table1 set field1= …

INSERT DELAYED INTO,是客戶端提交數據給MySQL,MySQL返回OK狀態給客戶端。而這是並不是已經將數據插入表,而是存儲在內存裡面等待排隊。

當mysql有空餘時,再插入。另一個重要的好處是,來自許多客戶端的插入被集中在一起,並被編寫入一個塊。這比執行許多獨立的插入要快很多。

壞處是,不能返回自動遞增的ID,以及系統崩潰時,MySQL還沒有來得及插入數據的話,這些數據將會丟失。並且導致last_insert_id()無法正常工作。


強制連接順序straight_join

SELECT TABLE1.FIELD1, TABLE2.FIELD2 FROM TABLE1 STRAIGHT_JOIN TABLE2 WHERE...;

由上面的SQL語句可知,通過STRAIGHT_JOIN強迫MySQL按TABLE1、TABLE2的順序連接表。如果你認為按自己的順序比MySQL推薦的順序進行連接的效率高的話,就可以通過STRAIGHT_JOIN來確定連接順序。

分組使用臨時表SQL_BIG_RESULT和SQL_SMALL_RESULT


SELECT SQL_BUFFER_RESULT FIELD1, COUNT(*) FROM TABLE1 GROUP BY FIELD1;

這兩個提示只對select語句有效,它們告訴優化器對group by 或者distinct 查詢如何使用臨時表及排序。

sql_small_result 告訴優化器結果集會很小,可以將結果集放在內存中的索引臨時表,以避免排序操作;

sql_big_result 則告訴優化器結果集會很大,建議使用磁盤臨時表做排序操作;


強制使用臨時表sql_buffer_result

SELECT SQL_BUFFER_RESULT * FROM TABLE1 WHERE …;

這個提示告訴優化器將查詢放入到一個臨時表,然後儘可能地釋放鎖。這和前面提到的由客戶端緩存結果不同。當你設法使用客戶端緩存的時候,使用服務器端的緩存通常很有效。

帶來的好處是無須在客戶端消耗太多的內存,還可以盡可能快的釋放對應的表鎖。代價是,服務器端需要更多的內存。


SQL_NO_CACHE

SQL_NO_CACHE hint 會使用特殊的查詢來關閉MySQL內置的查詢緩存機制。在動態性很強或者執行頻率很低的查詢上使用SQL_NO_CACHE hint,可以幫助MySQL提高緩存的使用效率。不過確保在使用SQL_NO_CACHE hint時,MySQL已經開啟了查詢緩存,否則沒有必要使用。

SELECT SQL_NO_CACHE field1, field2 FROM TABLE1;

關於MySQL查詢緩存的更多信息可以查看這裡


SQL_CACHE

如果你已經配置了query_cache_type = 2(僅在使用SQL_CACHE時進行緩衝),那麼可以使用SQL_CACHE hint來告訴MySQL哪些查詢需要進行緩存。

SELECT SQL_CALHE * FROM TABLE1;


sql_calc_found_rows

嚴格來說,這並不是一個優化器提示。它不會告訴優化器任何關於執行計劃的東西。

它會讓mysql返回的結果集包含更多的信息。查詢中加上該提示,mysql會計算出去limit子句後這個查詢返回的結果集的總數。

而實際上只返回limit要求的結果集。可以通過函數found_row()獲得這個值。


鎖相關for update 和lock in share mode

這兩個提示主要控制select 語句的鎖機制。但只對實現了行級鎖的存儲引擎有效。使用該提示會對符合查詢條件的數據加鎖。

對於insert...select 語句不需要這兩個提示,因為會默認添加上鎖。

唯一內置的支持這兩個提示的引擎是innoDB。另外需要記住的是,這兩個提示會讓某些優化無法進行。例如索引覆蓋掃描。

Laravel 點數系統的並發一致性:從 Redis Lock 到真正的 Concurrency Test

  Laravel 點數系統的並發一致性:從 Redis Lock 到真正的 Concurrency Test 您可以透過以下  GitHub  連結檢閱本專案的原始碼: https://github.com/BpsEason/loyalty-api.git 在點數系統裡,「加點...