Awesome Online Exercises
前言
記錄一些好玩的線上練習網站
CSS
Git
HTTP
Network
- The Case of the Slow Websites
- The Case of the Connection Timeout
- The Case of the DNS Update that Didn’t Work
- The Case of the 50ms Request
記錄一些好玩的線上練習網站
因為不小心手殘把 local 的 Hexo 設定砍了..
所以藉此來紀念我的手殘及記錄一下我的 Hexo blog 做了哪些設定
安裝套件
1 | npm install --save hexo-deployer-git |
調整 _config.yml
1 | deploy: |
安裝 NexT
1 | npm install hexo-theme-next --save |
將 NexT 的設定檔複製出來
1 | cp node_modules/hexo-theme-next/_config.yml _config.next.yml |
把 _config.yml 中的 theme 改成使用 NexT
1 | theme: next |
1 | npm install hexo-generator-sitemap --save |
1 | npm install hexo-filter-nofollow --save |
安裝套件
1 | npm install hexo-all-minifier --save |
在 _config.yml 中加入這個
1 | all_minifier: true |
1 | npm install hexo-generator-searchdb --save |
把 busuanzi_count 的 enable 改成 true
1 | busuanzi_count: |
(23) 試著學 Hexo - SEO 篇 - 新增你的 404 頁面
1 | npm install hexo-generator-topindex --save |
在面試的時候被問到 GIL,雖然我是直接回答說我看不懂,但是仔細想想上一次看也是快一年前了,於是想趁報到前再來挑戰一次 GIL
主要會分兩個部分來講
In CPython, the global interpreter lock, or GIL, is a mutex that protects access to Python objects, preventing multiple threads from executing Python bytecodes at once. The GIL prevents race conditions and ensures thread safety. A nice explanation of how the Python GIL helps in these areas can be found here. In short, this mutex is necessary mainly because CPython’s memory management is not thread-safe.
簡單來說,GIL 是一個 mutex,用來避免在 multi-threading 的情況下發生 race condition 並確保 thread safety
source: https://wiki.python.org/moin/GlobalInterpreterLock
這邊又出現了三個名詞:
接著先讓我們搞懂這三個東西是什麼再接著說下去
因為其他兩個名詞都跟 race condition 有關,所以在講其他兩個之前我們得先了解 race condition 是什麼
multi-threading 的情況下,每個 thread 的資源是共享的,所以不同的 thread 可以同時讀寫同一個變數,這樣就會造成程式輸出的結果有可能會因為不同 thread 執行的先後而導致輸出完全不一樣,例如:
我們現在用兩個 thread 跑同樣的程式 count++,假設兩個 thread 分別是 t1, t2,執行程式的過程都是一樣,要經過下面這兩步
那當執行順序是這樣的話
count 預設值為 0
我們原本的預期行為是 count = 2,但是因為變數共用再加上這樣的執行順序就有可能導致 count = 1,這樣的狀況我們就稱為 race condition
Mutex 就是一種避免發生 race condition 的方式,它的做法就是把共用的區塊加上一把鎖,在有其中一個 thread 正在讀寫這個區塊時,其他的 thread 就不能讀寫這個區塊,加上去後上面的狀況就會變成這樣
這樣的值就跟我們預期中的一樣了
可以簡單理解成,不會發生 race condition 的狀況就是 thread safety
了解 GIL 是什麼後,我們就可以來看一下所以 GIL 造成什麼影響
這邊我們要先分成 I/O bound 跟 CPU bound 兩種不同類型的程式來看
I/O bound
在 I/O bound 的程式下,只要執行 blocking 的 system call,系統就會釋放 CPU 資源給其他 thread 使用,所以 GIL 對 I/O bound 的影響並不大
CPU bound
CPU bound 這邊要再分成單核跟多核的狀況來看
在單核的狀況下就是不同的 thread 輪流使用 CPU 資源,整體上除了跑起來從原本預期的 parallel 變成 concurrent 之外沒什麼太大的影響
但是在多核的狀況下,如果兩個執行 CPU bound 任務的 thread 在不同的核心上執行,也許會出現以下的情況,其中一個核心上的 thread 在拿到 GIL 後執行任務時,另一個核心上的 thread 不停的搶 GIL 失敗,於是該核心長期呈現瞎忙的狀況
GIL 只有在 CPython 上有,所以可以換其他的 interpreter,如:PyPy、Jython,如果在不能換掉 CPython 的狀況下,可以改用 multi-processing 跑 CPU bound 的任務
面試的時候被考到一題情境題覺得蠻有趣的,於是決定記錄下來
面試官:今天有一個網站是 3-tier 的架構(前端、後端、資料庫),某天你發現首頁 load 不出來,這時候你會怎麼做?
我:打開瀏覽器的 console 看 network 那邊的 request 狀態是怎樣
面試官:你打開了,看到 request 沒有回傳 response,就卡著
我:這樣看起來是後端掛了,先檢查後端的 log
面試官:後端沒有 log,但是這個 controller 只有跟 db 撈資料,其他都沒有做
我:那應該是後端跟 db 溝通的時候卡住了,這張表很大嗎?
面試官:大概 10 萬筆
我:那應該還好,db 那台的 memory 跟 CPU 都是健康的嗎?
面試官:CPU 跟 memory 的 usage 都不超過 30%
我:db 是 RDS 嗎?
面試官:是
我:RDS 可以看每條 query 跑的狀況,這條 query 跑的狀況有異常嗎?
面試官:前幾次跑都沒問題,但是這次掛了
我:…
面試官:那現在是什麼問題?你需要一點提示嗎?
我:好,我要提示
面試官:你手動連接 db 發現連不進去了
我:那應該是 connection pool 沒設定好,需要檢查一下 connection pool 的設定
面試官:好,那今天你把 connection pool 調小一點,然後 bug 解掉了,但是過幾個月後流量暴增,現在服務又卡住了,你要怎麼優化?
我:SQL 是讀寫都有,還是只有讀而已?
面試官:只有讀
我:對 db 做 replica
面試官:OK,這樣問題解掉了,但是你的解法很浪費資源,因為效能瓶頸是卡在 db,不是後端流量被灌爆,但是你為了 replica,後端也要新開一台出來,但是大部分時間後端的利用率是很低的,你還有其他方法嗎?
我:有錢嗎?
面試官:老闆說,錢管夠
我:機器多開幾台
面試官:這是一個方法沒錯,還有其他的方法嗎?
我:優化 SQL 的寫法,然後加上 cache
面試官:你的 cache 打算怎麼做?
我:在後端做 cache
面試官:cache 的 key 是什麼
我:我應該會用頁面當作 key
面試官:OK 看起來應該差不多了
這是一次蠻新鮮的面試經驗,以前從沒被這樣考過,但是我還挺喜歡這種考法的,很貼近現實,而且考得層面很廣,考完一次大概就可以知道你大概懂哪些東西,哪邊地方比較弱,雖然這次考得算是我比較弱的 db 部分,但是在面試官的引導下還算是過關了
以下是我把對話中的問題整理過,然後需要哪些方面的知識
HTTP 的 method 中最常被用到的應該就是 GET 及 POST 了
但是 GET 與 POST 除了使用場景不一樣之外,到底還有哪些區別呢?
我們知道 GET 通常都透過 query string 來傳遞參數,POST 則是使用 request body
但是其實 GET 也可以透過 request body 來傳遞參數,同理 POST 其實也能使用 query string(只是上述兩種方式都不推薦)
所以具體的差別不在於透過什麼方式傳遞參數,而在於以下幾點
HTTPS 會加密 path, query string, request body
但是 domain name 不一定會加密(如果沒有使用 SNI 才會把 domain name 加密)
最近常常在用 Python 寫爬蟲
就好奇 BeautifulSoup 不同的 Parser 之間有什麼差別
於是寫了這篇文來記錄一下
1 | import requests |
網路上的爬蟲教學常常會看到以上兩種寫法,可以看到差別就是 html.parser 跟 lxml
這個其實是在跟 BeautifulSoup 說我們要用哪種 Parser 去解析 HTML
但是到底 BeautifulSoup 支援多少種 Parser,及每種 Parser 到底差在哪?
於是就隨手 google 了一下發現了 StackOverflow 上的這篇及 BeautifulSoup 的 doc
以下是不同的 Parser 的比較表格
tl;dr
速度最快:lxml
相容性最高:html5lib
剩下用:html.parser
Parser | 優點 | 缺點 |
---|---|---|
html.parser | Python 內建,不需額外安裝 | 速度跟相容性都普通 |
lxml | 快 | 需要額外安裝(C dependency) |
html5lib | 相容性最高,所有版本的 Python 都能用 | 慢 |
最近在 build docker image 的時候遇到 No space left on device 的問題
因為在解的過程發現好像蠻多人都有遇過這個問題,於是就把解的過程記錄下來,希望能幫到其他人
今天在 build docker image 的時候出現這個錯誤
1 | ERROR: Could not install packages due to an EnvironmentError: [Errno 28] No space left on device |
因為是死在 pip install 這關,所以一開始先往 pip 的方向去找找到了以下這篇
[Errno 28] No space left on device #5816
裡面看起來是在說當不是用 root 安裝時,會遇到 tmp 資料夾空間不足的問題,裡面大概提供了兩種解法:
最後覺得第一個太麻煩了(因為我是在 docker 裡面),所以選第二個
但是問題沒解決,接著只把這段再加上 docker 拿去餵狗
1 | No space left on device |
接著看到好像真的是 docker 的問題,因為蠻多人都遇過的
看起來是因為 docker 會先配置一些空間用來暫存資料,然後這個空間被塞爆後就會報這個錯誤
於是我看了這篇
Docker error : no space left on device
然後先試了
1 | > docker system prune |
可以從輸入後的結果來看到這個指令將會刪除
如果上面這些東西還有要用的話這條路可能就行不通
總之我執行了之後空間好像還是不夠
接著照著這篇
https://success.docker.com/article/no-space-left-on-device-error
先找出哪些 container 的 log 檔最大
1 | du -d1 -h /var/lib/docker/containers | sort -h |
大概會看到這種東西
1 | 36K /var/lib/docker/containers/46d7350f4e7cd7c5c473ace07a58b74e20cb2edff7c2484c5a6e547f86ce17f3 |
找出最佔空間的 log 檔,然後搭配
1 | docker ps |
確定是哪個 container 的 log 檔且確定不需要了之後執行以下指令來清除 log 檔
1 | cat /dev/null > /var/lib/docker/containers/<container_id>/<container_log_name> |
如果權限不足的話可能要用以下指令
1 | sudo sh -c "cat /dev/null > /var/lib/docker/containers/<container_id>/<container_log_name>" |
刪完後再執行一次以下指令確認 log 檔已經被刪除
1 | du -d1 -h /var/lib/docker/containers | sort -h |
然後…還是失敗,於是決定換個思路
1 | df |
結果原來是 ubuntu 的空間快被吃光了..
然後照著這篇做
7 Simple Ways to Free Up Space on Ubuntu and Linux Mint
先清 apt
1 | sudo apt-get autoremove |
接著清 log
1 | # 看 log 檔佔多少空間 |
再 build 一次就成功了QQ