一、單選題(共10題,每題5分)
1..以下代碼輸出的結果是?
$a=[0,1,2,3]; $b=[1,2,3,4,5]; $a+=$b; echo json_encode($a);
PHP
A、[0,1,2,3]
B、[1,3,5,7,5]
C、[1,2,3,4,5]
D、[0,1,2,3,5]
參考答案:D
答案解析:
考的是數組+和array_merge的區別 當下標為數值時,array_merge()不會覆蓋掉原來的值,但array+array合並數組則會把最先出現的值作為最終結果返回,而把后面的數組擁有相同鍵名的那些值“拋棄”掉(不是覆蓋). 當下標為字符時,array+array仍然把最先出現的值作為最終結果返回,而把后面的數組擁有相同鍵名的那些值“拋棄”掉,但array_merge()此時會覆蓋掉前面相同鍵名的值.
2..以下代碼執行結果是?
$count = 5;function get_count(){
static $count = 0;
return $count++;}++$count;get_count();echo get_count();
PHP
A、0
B、1
C、2
D、3
參考答案:B
答案解析:
如果你回答 2 ,恭喜,你掉入陷阱了。 其實這道題主要考兩點,第一點是static靜態類型。這種的值永遠都是靜態的,第一次調用聲明等於0,並且自增等於1。第二次調用,1再自增就等於2。但其實這里還有一道陷阱,那就是++a與a++的區別,前++是先自增,后++是先返回值再自增,所以結果等於 1。
3.以下PHP代碼執行的結果是?
$a=[1,2,3]; foreach($a as &$v){
} foreach($a as $v){
} echo json_encode($a);
PHP
A、[1,2,3]
B、[1,2,2]
C、[1,1,2]
D、[1,3,2]
參考答案:B
答案解析:
在 PHP 中,foreach 結束后,循環中的索引值(index)及內容(value)並不會被重置。 所以最后的 $v還指向最后一個元素,再次循環,就會把最后個元素的值修改掉了。
解決的辦法是,循環完畢之后,用unset($v); https://www.php.net/manual/en/control-structures.foreach.php
4.php執行過程的順序正確的是?
A、掃描->解析->編譯->執行->輸出
B、掃描->解析->執行->編譯->輸出
C、掃描->編譯->解析->執行->輸出
D、掃描->執行->編譯->解析->輸出
參考答案:A
答案解析:
PHP簡化執行過程: 1.掃描(scanning) ,將index.php內容變成一個個語言片段(token) 2.解析(parsing) , 將一個個語言片段變成有意義的表達式 3.編譯(complication),將表達式編譯成中間碼(opcode) 4.執行(execution),將中間碼一條一條的執行 5.輸出(output buffer),將要輸出的內容輸出到緩沖區
5.php垃圾回收機制的說法錯誤的是?
A、在一個垃圾周期中,通過檢查引用計數是否減1,並且檢查哪些變量容器的引用次數是零,來發現哪部分是垃圾
B、可以通過調用gc_enable() 和 gc_disable()函數來打開和關閉垃圾回收機制
C、通過清理未被使用的變量來節省內存的占用
D、php代碼執行完畢后會自動執行垃圾回收,所以不需要手動執行垃圾回收
參考答案:D
答案解析:
php一段代碼有可能要長時間執行,但若此期間有未引用的變量的話,就會占用內存的空間,導致運行緩慢等問題
6.關於XSS防御,錯誤的是?
A、禁止字符
B、限制字符(reg_match)
C、過濾(preg_replace)
D、轉義標簽(htmlspecialchars)
參考答案:A
答案解析:
轉義標簽(htmlspecialchars) 限制字符(reg\_match) 過濾(preg\_replace) http only 模板引擎
7.有一個文件ip.txt,每行一條ip記錄,共若干行,下面哪個命令可以實現“統計出現次數最多的前3個ip及其次數”?( )
A、uniq -c ip.txt
B、sort -nr ip.txt | uniq -c | sort -nr | head -n 3
C、cat ip.txt | count -n | sort -rn | head -n 3
D、cat ip.txt | count -n
參考答案:B
答案解析:
本題利用管道符"|"組合多個命令,uniq -c filename用於去除冗余並統計每一行出現的次數。 sort -r指逆序排序,-n指按數字字符串大小排序 head指定數量。 剩下的二選一交給運氣。
正確的命令應該為: sort -nr ip.txt | uniq -c | sort -nr | head -n 3 第一次排序,把ip按順序排列,因為第二個uniq只會合並相鄰項 第二次排序,才是把ip按出現次序大小從大到小排列 最后取前三項結果。
8.Mysql索引使用的B-Tree描述錯誤的是?
A、每個非葉子結點由n-1個key和n個指針組成,其中d<=n<=2d;
B、每個葉子結點至少包含一個key和兩個指針
C、所有葉結點都在同一層,深度等於樹高h
D、一個結點中的key從左至右遞減排列
參考答案:D
答案解析:
B-Tree是滿足條件: d>=2,即B-Tree的度; h為B-Tree的高; 每個非葉子結點由n-1個key和n個指針組成,其中d
9.下列哪個是創建一個每周三01:00~04:00每3分鍾執行執行一次的crontab指令?
A、* 1,4 * * 3 /bin/bash /home/sijiaomao/ok.sh
B、*/3 1,4 * * 3 /bin/bash /home/sijiaomao/ok.sh
C、*/3 1-4 * * 3 /bin/bash /home/sijiaomao/ok.sh
D、*/3 1-4 * * * /bin/bash /home/sijiaomao/ok.sh
參考答案:C
答案解析:
A:每周三的1時4時每分鍾執行一次 B:每周三的1時4時每3分鍾執行一次 C:滿足要求 D:每天的1時4時每3分鍾執行一次
10.正則的引擎表述錯誤的是?
A、正則引擎主要可以分為兩大類:一種是DFA,一種是NFA。
B、一般而論,NFA引擎則搜索更快一些。但是DFA以表達式為主導,更容易操縱,因此一般程序員更偏愛DFA引擎!
C、NFA表達式主導,DFA文本主導.
D、可以使用是否支持忽略優先量詞和分組捕獲來判斷引擎類型:支持 NFA,不支持 DFA
參考答案:B
答案解析:
正確的說法應該是:一般而論,DFA引擎則搜索更快一些。但是NFA以表達式為主導,更容易操縱,因此一般程序員更偏愛NFA引擎!
二、多選題(共10題,每題5分)
1.HTTP中GET與POST的區別有哪些?
A、GET在瀏覽器回退時是無害的,而POST會再次提交請求
B、GET請求只能進行url編碼,而POST支持多種編碼方式
C、GET請求會被瀏覽器主動cache,而POST不會,除非手動設置。
D、GET產生一個TCP數據包,POST產生兩個TCP數據包。
參考答案:A,B,C,D
答案解析:
HTTP中GET與POST的區別如下,注意最后一條
GET在瀏覽器回退時是無害的,而POST會再次提交請求。
GET產生的URL地址可以被Bookmark,而POST不可以。
GET請求會被瀏覽器主動cache,而POST不會,除非手動設置。
GET請求只能進行url編碼,而POST支持多種編碼方式。
GET請求參數會被完整保留在瀏覽器歷史記錄里,而POST中的參數不會被保留。
GET請求在URL中傳送的參數是有長度限制的,而POST沒有。
對參數的數據類型,GET只接受ASCII字符,而POST沒有限制。
GET比POST更不安全,因為參數直接暴露在URL上,所以不能用來傳遞敏感信息。
GET參數通過URL傳遞,POST放在Request body中。
GET產生一個TCP數據包,POST產生兩個TCP數據包。
關於最后一條,詳情參考 https://blog.csdn.net/happy_xiahuixiax/article/details/72859762
2.MySQL有一個復合索引:INDEX(`a`, `b`, `c`),以下查詢能用上索引的有?
A、select * from users where a = 1 and b = 2
B、select * from users where b = 2 and a = 1
C、select * from users where a = 2 and c = 1
D、select * from users where b = 2 and c = 1
參考答案:A,B,C
答案解析:
請牢記最左前綴原則
使用方式 能否用上索引
select * from users where a = 1 and b = 2 能用上a、b
select * from users where b = 2 and a = 1 能用上a、b(有MySQL查詢優化器)
select * from users where a = 1 and b = 2 能用上a
select * from users where a = 1 and b = 2 不能
選項D 無法用上索引。
3.為什么大型網站要使用消息隊列?
A、解耦
B、異步
C、削峰
D、大數據處理
參考答案:A,B,C
答案解析:
消息隊列常見的使用場景有很多,但是比較核心的有 3 個:解耦、異步、削峰 大數據處理,有相應的處理辦法,和消息隊列關系不大。
4.關於Memcache與Redis的說法正確的有?
A、Memcache單個key(變量)存放的數據有2M的限制, Redis單個key(變量)存放的數據有1GB的限制
B、Memcache存儲數據的類型都是String類型,Redis數據類型比較豐富:String、List、Set、Sortedset、Hash
C、Memcache可以使用多核(多線程),而Redis只是支持單線程
D、Memcache服務器突然斷電,則全部數據就會丟失; 而Redis有持久化功能,可以把數據隨時存儲在磁盤上
參考答案:B,C,D
答案解析:
Memcache
該產品本身特別是數據在內存里邊的存儲,如果服務器突然斷電,則全部數據就會丟失
單個key(變量)存放的數據有1M的限制
存儲數據的類型都是String字符串類型
本身沒有持久化功能
可以使用多核(多線程)
Redis
數據類型比較豐富:String、List、Set、Sortedset、Hash
有持久化功能,可以把數據隨時存儲在磁盤上
本身有一定的計算功能
單個key(變量)存放的數據有1GB的限制
選項A 說Memcache單個key(變量)存放的數據有2M的限制是不對的。
5關於緩存雪崩的事前事中事后的解決方案正確的有?
A、事前:進行系統壓力測試,在負載均衡層做限流處理,過載丟棄請求或者進入隊列
B、事前:redis 高可用,主從+哨兵,redis cluster,避免全盤崩潰。
C、事中:本地 ehcache 緩存 + hystrix 限流&降級,避免 MySQL 被打死。
D、事后:redis 持久化,一旦重啟,自動從磁盤上加載數據,快速恢復緩存數據。
參考答案:A,B,C,D
答案解析:
緩存雪崩的事前事中事后的解決方案如下。
事前:進行系統壓力測試,在負載均衡層做限流處理,過載丟棄請求或者進入隊列
事前:redis 高可用,主從+哨兵,redis cluster,避免全盤崩潰。
事中:本地 ehcache 緩存 + hystrix 限流&降級,避免 MySQL 被打死。
事后:redis 持久化,一旦重啟,自動從磁盤上加載數據,快速恢復緩存數據。
6.設計一個高並發系統,需要重點考慮的問題有?
A、系統拆分
B、緩存
C、MQ
D、分庫分表
E、讀寫分離
F、ElasticSearch
參考答案:A,B,C,D,E,F
答案解析:
如何設計一個高並發系統?
系統拆分 將一個系統拆分為多個子系統,用 dubbo 來搞。然后每個系統連一個數據庫,這樣本來就一個庫,現在多個數據庫,不也可以扛高並發么。
緩存 緩存,必須得用緩存。大部分的高並發場景,都是讀多寫少,那你完全可以在數據庫和緩存里都寫一份,然后讀的時候大量走緩存不就得了。畢竟人家 redis 輕輕松松單機幾萬的並發。所以你可以考慮考慮你的項目里,那些承載主要請求的讀場景,怎么用緩存來抗高並發。
MQ MQ,必須得用 MQ。可能你還是會出現高並發寫的場景,比如說一個業務操作里要頻繁搞數據庫幾十次,增刪改增刪改,瘋了。那高並發絕對搞掛你的系統,你要是用 redis 來承載寫那肯定不行,人家是緩存,數據隨時就被 LRU 了,數據格式還無比簡單,沒有事務支持。所以該用 mysql 還得用 mysql 啊。那你咋辦?用 MQ 吧,大量的寫請求灌入 MQ 里,排隊慢慢玩兒,后邊系統消費后慢慢寫,控制在 mysql 承載范圍之內。所以你得考慮考慮你的項目里,那些承載復雜寫業務邏輯的場景里,如何用 MQ 來異步寫,提升並發性。MQ 單機抗幾萬並發也是 ok 的,這個之前還特意說過。
分庫分表 分庫分表,可能到了最后數據庫層面還是免不了抗高並發的要求,好吧,那么就將一個數據庫拆分為多個庫,多個庫來扛更高的並發;然后將一個表拆分為多個表,每個表的數據量保持少一點,提高 sql 跑的性能。
讀寫分離 讀寫分離,這個就是說大部分時候數據庫可能也是讀多寫少,沒必要所有請求都集中在一個庫上吧,可以搞個主從架構,主庫寫入,從庫讀取,搞一個讀寫分離。讀流量太多的時候,還可以加更多的從庫。
ElasticSearch Elasticsearch,簡稱 es。es 是分布式的,可以隨便擴容,分布式天然就可以支撐高並發,因為動不動就可以擴容加機器來扛更高的並發。那么一些比較簡單的查詢、統計類的操作,可以考慮用 es 來承載,還有一些全文搜索類的操作,也可以考慮用 es 來承載。
上面的 6 點,基本就是高並發系統肯定要干的一些事兒,大家可以仔細結合之前講過的知識考慮一下,到時候你可以系統的把這塊闡述一下,然后每個部分要注意哪些問題,之前都講過了,你都可以闡述闡述,表明你對這塊是有點積累的。
說句實話,畢竟你真正厲害的一點,不是在於弄明白一些技術,或者大概知道一個高並發系統應該長什么樣?其實實際上在真正的復雜的業務系統里,做高並發要遠遠比上面提到的點要復雜幾十倍到上百倍。你需要考慮:哪些需要分庫分表,哪些不需要分庫分表,單庫單表跟分庫分表如何 join,哪些數據要放到緩存里去,放哪些數據才可以扛住高並發的請求,你需要完成對一個復雜業務系統的分析之后,然后逐步逐步的加入高並發的系統架構的改造,這個過程是無比復雜的,一旦做過一次,並且做好了,你在這個市場上就會非常的吃香。
其實大部分公司,真正看重的,不是說你掌握高並發相關的一些基本的架構知識,架構中的一些技術,RocketMQ、Kafka、Redis、Elasticsearch,高並發這一塊,你了解了,也只能是次一等的人才。對一個有幾十萬行代碼的復雜的分布式系統,一步一步架構、設計以及實踐過高並發架構的人,這個經驗是難能可貴的。
7.關於PHP-FPM子進程數量說法正確的有?
A、PHP-FPM 子進程數量不能太多,太多了增加進程管理的開銷以及上下文切換的開銷
B、dynamic 方式下,最合適的子進程數量為 在 N + 20% 和 M / m 之間 (N 是 CPU 內核數量,M 是 PHP 能利用的內存數量,m 是每個 PHP 進程平均使用的內存數量)
C、static方式:M / (m * 1.2) (M 是 PHP 能利用的內存數量,m 是每個 PHP 進程平均使用的內存數量)
D、pm.max_requests 可以隨便設置 ,但是為了預防內存泄漏的風險,還是設置一個合理的數比較好
參考答案:A,B,C,D
答案解析:
首先,我們關注下 PHP-FPM 的運行方式:
static :表示在 php-fpm 運行時直接 fork 出 pm.max_chindren 個子進程,
dynamic:表示,運行時 fork 出 start_servers 個進程,隨着負載的情況,動態的調整,最多不超過 max_children 個進程。
一般推薦用 static ,優點是不用動態的判斷負載情況,提升性能;缺點是多占用些系統內存資源。
PHP-FPM 子進程數量,是不是越多越好? 當然不是,pm.max_chindren,進程多了,增加進程管理的開銷以及上下文切換的開銷。更核心的是,能並發執行的 php-fpm 進程不會超過 cpu 個數。如何設置,取決於你的代碼。如果代碼是 CPU 計算密集型的,pm.max_chindren 不能超過 CPU 的內核數。如果不是,那么將 pm.max_chindren 的值大於 CPU 的內核數,是非常明智的。國外技術大拿給出適用於 dynamic 方式的公式: 在 N + 20% 和 M / m 之間。
.N 是 CPU 內核數量。
.M 是 PHP 能利用的內存數量。
.m 是每個 PHP 進程平均使用的內存數量。
*static方式的公式:M / (m 1.2)**
當然,還有一種保險的方式,來配置 max_children。 先把 max_childnren 設置成一個比較大的值。穩定運行一段時間后,觀察 php-fpm 的 status 里的 max active processes 是多少,然后把 max_children 配置比它大一些就可以了。
pm.max_requests:指的是每個子進程在處理了多少個請求數量之后就重啟。這個參數,理論上可以隨便設置,但是為了預防內存泄漏的風險,還是設置一個合理的數比較好。
8.關於Kafka、ActiveMQ、RabbitMQ、RocketMQ說法正確的有?
A、ActiveMQ 基於 erlang 開發,並發能力很強,性能極好,延時很低
B、RocketMQ topic 可以達到幾百/幾千的級別,吞吐量會有較小幅度的下降,在同等機器下,可以支撐大量的 topic
C、RabbitMQ時效性是微秒級,這是 RabbitMQ 的一大特點,延遲最低
D、Kafka 單機吞吐量 10 萬級,高吞吐,一般配合大數據類的系統來進行實時數據計算、日志采集等場景
參考答案:B,C,D
答案解析:
ActiveMQ 基於 Java 開發的, RabbitMQ 是基於 erlang 開發的。 所以選項A 錯誤。 B、C、D都正確。
特性 ActiveMQ RabbitMQ RocketMQ Kafka
單機吞吐量 萬級,比 RocketMQ、Kafka 低一個數量級 同 ActiveMQ 10 萬級,支撐高吞吐 10 萬級,高吞吐,一般配合大數據類的系統來進行實時數據計算、日志采集等場景
topic 數量對吞吐量的影響 topic 可以達到幾百/幾千的級別,吞吐量會有較小幅度的下降,這是 RocketMQ 的一大優勢,在同等機器下,可以支撐大量的 topic topic 從幾十到幾百個時候,吞吐量會大幅度下降,在同等機器下,Kafka 盡量保證 topic 數量不要過多,如果要支撐大規模的 topic,需要增加更多的機器資源
時效性 ms 級 微秒級,這是 RabbitMQ 的一大特點,延遲最低 ms 級 延遲在 ms 級以內
可用性 高,基於主從架構實現高可用 同 ActiveMQ 非常高,分布式架構 非常高,分布式,一個數據多個副本,少數機器宕機,不會丟失數據,不會導致不可用
消息可靠性 有較低的概率丟失數據 基本不丟 經過參數優化配置,可以做到 0 丟失 同 RocketMQ
功能支持 MQ 領域的功能極其完備 基於 erlang 開發,並發能力很強,性能極好,延時很低 MQ 功能較為完善,還是分布式的,擴展性好 功能較為簡單,主要支持簡單的 MQ 功能,在大數據領域的實時計算以及日志采集被大規模使用
9.分庫分表之后,id 主鍵如何處理?
A、單庫生成自增 id
B、設置數據庫 sequence 或者表自增字段步長
C、UUID
D、snowflake 算法
參考答案:A,B,C,D
答案解析:
snowflake 算法
A、B、C 也是理論可行的,但是都各自有缺點,最好用snowflake 算法。
snowflake 算法是 twitter 開源的分布式 id 生成算法,采用 Scala 語言實現,是把一個 64 位的 long 型的 id,1 個 bit 是不用的,用其中的 41 bit 作為毫秒數,用 10 bit 作為工作機器 id,12 bit 作為序列號。
1 bit:不用,為啥呢?因為二進制里第一個 bit 為如果是 1,那么都是負數,但是我們生成的 id 都是正數,所以第一個 bit 統一都是 0。 41 bit:表示的是時間戳,單位是毫秒。41 bit 可以表示的數字多達 2^41 - 1,也就是可以標識 2^41 - 1 個毫秒值,換算成年就是表示69年的時間。 10 bit:記錄工作機器 id,代表的是這個服務最多可以部署在 2^10台機器上哪,也就是1024台機器。但是 10 bit 里 5 個 bit 代表機房 id,5 個 bit 代表機器 id。意思就是最多代表 2^5個機房(32個機房),每個機房里可以代表 2^5 個機器(32台機器)。 12 bit:這個是用來記錄同一個毫秒內產生的不同 id,12 bit 可以代表的最大正整數是 2^12 - 1 = 4096,也就是說可以用這個 12 bit 代表的數字來區分同一個毫秒內的 4096 個不同的 id。
10.Redis 內存淘汰機制有哪些?
A、noeviction: 當內存不足以容納新寫入數據時,新寫入操作會報錯
B、allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的 key
C、volatile-lru:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,移除最近最少使用的 key
D、allkeys-random:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,隨機移除某個 key。
參考答案:A,B,C
答案解析:
redis 內存淘汰機制有以下幾個:
noeviction: 當內存不足以容納新寫入數據時,新寫入操作會報錯,這個一般沒人用吧,實在是太惡心了。 allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的 key(這個是最常用的)。 allkeys-random:當內存不足以容納新寫入數據時,在鍵空間中,隨機移除某個 key,這個一般沒人用吧,為啥要隨機,肯定是把最近最少使用的 key 給干掉啊。 volatile-lru:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,移除最近最少使用的 key(這個一般不太合適)。 volatile-random:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,隨機移除某個 key。 volatile-ttl:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,有更早過期時間的 key 優先移除。