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");
沒有留言:
張貼留言