跳至主要内容

· 閱讀時間約 3 分鐘
junminhong(jasper)

問題

今天遇到一個很神奇的問題, 如往常一樣執行

bundle install

# 如果想知道更詳細的bundle安裝細節可以多加--verbose
bundle install --verbose

發現, 有三個 gem 一直無法正常安裝

  • debase
  • ruby-debug-ide
  • libv8-node

排查問題

於是排查了一下 log, 可以找到以下幾個關鍵字, 蠻明顯可以看出 complier 這塊可能出點問題, 那因為筆者是使用 macOS , 所以可以很快地聯想到應該是 xcode command line tool

note: expanded from macro 'rb_intern'
__extension__ (RUBY_CONST_ID_CACHE((ID), (str))) : \
^
15 warnings and 2 errors generated.
make: *** [debase_internals.o] Error 1

make failed, exit code 2

於是乎呢, 我就先重新安裝一下 xcode command line tool 看能不能解決這個問題, 如何重新安裝可以參考這篇的步驟

但是事情並沒有想像中的這麼簡單...

那要怎麼解決呢?

到這邊各位可以稍微思考一下, 在透過 bundler 安裝這些 gem 的時候, 做了哪些事情, 這邊可以透過 bundle install 觀察一下有哪些負載很重的 process, 細心的各位其實可以看到 clang 這個東西此時會佔用蠻大量的CPU使用率

那也就是說可以把問題點收斂到這個區塊上, 首先可以先檢查自己電腦裡面的 clang version

clang -v

# get clang information
# 如果沒有透過Homebrew額外安裝llvm, 這邊應該會顯示的是xcode command line tool本身帶的
Homebrew clang version xx.x.x
Target: arm64-apple-darwin23.3.0 <= 會根據 macOS 不同
Thread model: posix
InstalledDir: xxx <= 安裝的位置

從取得的資訊裡面來看會發現我是使用 Homebrew 額外安裝的 llvm, 於是乎我就先 llvm 降版再重做一次 bundle install, 就發現 竟 然 正 常 了...

結語

其實在排查這個問題的時候, 就已經想到是不是前幾天有針對系統的一些東西有做個升級導致, 但排查到後的結果沒想到竟然是 llvm 在搞鬼, 原先更新完的版本是17, 降成16發現還是不行, 果斷繼續往下降就好了...

奉勸各位, 就算容易踩坑, 但新版還是要追起來😆, 沒事真的不要亂升級😭

· 閱讀時間約 1 分鐘
junminhong(jasper)

問題

在使用 Elasticsearch 時, 如果某個 index 中的 field 有使用到 ik_max_word 分詞器, 但Elasticsearch 沒有安裝該 plugin, 就會出現以下訊息

Custom Analyzer [synonym] failed to find tokenizer under name [ik_max_word]"}

解決步驟

  1. 進入elasticsearch container
docker exec -it elasticsearch bash
  1. 根據不同版本的elasticsearch下載對應的ik plugin
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.17.0/elasticsearch-analysis-ik-7.17.0.zip

參考網址

· 閱讀時間約 2 分鐘
junminhong(jasper)

問題

最近 elasticsearch 常常出現 watermark 已滿的問題, 這問題是因為硬碟空間不夠觸發了elasticsearch 的 watermark 的保護機制, 會先暫時將 index 鎖住不給寫入, 但此時是可以讀取的

TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark, index has read-only-allow-delete block

解決步驟

  1. 優先將硬碟空間加大或者是清理空間, 可以善用 df、du 等指令去排查 disk space 並做清理
  2. 設定 elasticsearch watermark, default 是95%
curl -X PUT --user es_account:password "https://elasticsearch_domain/_cluster/settings?pretty" -H 'Content-Type: application/json' -d'
{
"persistent": {
"cluster.routing.allocation.disk.watermark.low": 97%,
"cluster.routing.allocation.disk.watermark.high": 97%,
"cluster.routing.allocation.disk.watermark.flood_stage": 97%
}
}
'
  1. 設定完等 elasticsearch 沒問題時要將 watermark 設定移除
curl -X PUT --user es_account:password "https://elasticsearch_domain/_cluster/settings?pretty" -H 'Content-Type: application/json' -d'
{
"persistent": {
"cluster.routing.allocation.disk.watermark.low": null,
"cluster.routing.allocation.disk.watermark.high": null,
"cluster.routing.allocation.disk.watermark.flood_stage": null
}
}
'

建議

  • 善用 Grafana 等監控隨時注意機器的硬碟空間, 避免空間爆了造成index被鎖住
  • 調整 index 的 lifecycle policy, 避免資料一直保存然後消耗過多的硬碟空間
  • 機器硬碟空間蠻貴的, 可以考慮用某些服務的 block storage 有提供HDD的選項, 可以節省花費, 或者可以考慮往S3、GCS等有提供較便宜儲存方式的服務去放 cold data

· 閱讀時間約 2 分鐘
junminhong(jasper)

nil?

  • provided by ruby

  • 可以使用在任何型別上

  • 只有nil才會return true, 否則return false

# 只有nil才會回傳true
nil.nil? => true

[].nil? => false
{}.nil? => false
0.nil? => false
false.nil? => false
"".nil? => false
" ".nil? => false

empty?

  • provided by ruby

  • 僅用於 Hash、Array、Set、String

  • 當沒有任何元素時才會return true, 否則return false

當你將empty? 使用在沒有該方法的類別上, 會得到NoMethodErrorexception, 所以你會需要使用檢查來避免程式在運行上不會崩潰

[].empty? => true
{}.empty? => true
Set.new.empty? => true
# 當用於string時, 可把他想像成bytes/characters的集合
"".empty? => true

" ".empty? => false

blank?

  • provided by rails(in ActiveSupport)

  • 可以使用在任何型別上

  • 任何false相關的情況都會回傳true, (如nil and false)

如同你所看到的, blank?empty? 更好用, 可以避免無法使用的資料處理上, 會回傳NoMethodErrors 錯誤

[].blank? => true
{}.blank? => true
Set.new.blank? => true
"".blank? => true
" ".blank? => true
false.blank? => true
nil.blank? => true

# 如果是Hash、Array、Set, 原理跟empty一樣, 如果沒有元素就回傳true
[nil].blank? => false
["", ""].blank? => false
{name: 'jasper'}.blank? => false
true.blank? => false

present?

  • provided by rails

  • blank?相反


true.present? => true
{name: 'jasper'}.present? => true
3.present? => true

false.present? => false
{}.present? => false
"".present? => false
" ".presnet? => false
[].present? => false
nil.present? => false

· 閱讀時間約 4 分鐘
junminhong(jasper)

前情提要

最近因為有就職博覽會的關係, 所以要根據系統進行壓力測試, 以確保當天是能夠容納瞬時流量的

於是乎呢, 將系統硬體規格做個調整並搭配壓測, 先找出符合需求的硬體規格

炸彈即將來襲

當我完成測試後, 要將目前規格還原至原本的規格, 於是乎就直接按下resize後等待

於是過了一段時間後...

我看到了RUNNING, 想說應該就沒事了, 結果當我要去打開網站的時候, 完全無法使用

於是我趕緊透過ssh連到server看一下發生了什麼事情, 結果發現ssh完全連不上去

刺激的拆彈之旅

  • 嘗試透過reboot, power on\off, 先確認能否解決問題, 發現並沒辦法解決

  • 使用linode提供的LISH console, 嘗試進入機器, 發現完全無法進入, 也發現了幾個錯誤, 初步研判可能是resize的時候有些資料出現問題

  • 這時候可以善用linode提供的緊急救援模式, 修復一下磁碟

    • 重新開機並透過ssh連線, 會發現現在透過Finnix成功進入系統
    # 看一下磁區
    dh -h

    # 如果沒有看到你的磁區才是正確的
    Filesystem Size Used Avail Use% Mounted on
    udev 1.9G 0 1.9G 0% /dev
    tmpfs 395M 516K 394M 1% /run
    /dev/sr0 503M 503M 0 100% /run/live/medium
    /dev/loop0 426M 426M 0 100% /run/live/rootfs/filesystem.squashfs
    tmpfs 2.0G 17M 2.0G 1% /run/live/overlay
    overlay 2.0G 17M 2.0G 1% /
    tmpfs 2.0G 0 2.0G 0% /dev/shm
    tmpfs 5.0M 0 5.0M 0% /run/lock
    tmpfs 4.0M 0 4.0M 0% /sys/fs/cgroup
    tmpfs 2.0G 0 2.0G 0% /tmp
    tmpfs 395M 0 395M 0% /run/user/0pressed_root
    unionfs 739M 1016K 738M 1% /
    devtmpfs 10M 0 10M 0% /dev
    • 使用e2fsck
    # 強制檢查, 然後有問題就直接選擇yes讓工具自己去修復
    e2fsck -f /dev/sda

    # 沒問題, 會出現這個訊息
    e2fsck 1.45.6 (20-Mar-2020)
    Pass 1: Checking inodes, blocks, and sizes
    Pass 2: Checking directory structure
    Pass 3: Checking directory connectivity
    Pass 4: Checking reference counts
    Pass 5: Checking group summary information
    /dev/sda: 44611/2564096 files (0.1% non-contiguous), 602550/10240000 blocks
  • 修復後直接重新啟動就可以再次透過ssh進入系統, 此時再根據其他錯誤去做相對應的調整即可

反思時間

  • 應該要先clone一起機器出來, 再搭配transfer ip直接切換機器即可, 不要再機器上面直接resize, 出事情會有點麻煩
  • 做任何事情前一定要做備份, 但還好平常就有在備份的習慣, 所以其實最壞的結果就是直接透過備份restore在換上去就好了
  • 扛著壓力, 將問題解決, 超讚的拉 😆

· 閱讀時間約 2 分鐘
junminhong(jasper)

起由

最近看到docusaurus發表了v3版本, 身為一個追求最新版的愛好者, 當然要來處理一下拉

這個版本除了MDX升級以外, 也淘汰了Node.js 16, 所以在升級前要確保目前使用的是Node.js 18.0+

首先呢, 要來做套件升級

 {
"dependencies": {
// upgrade to Docusaurus v3
- "@docusaurus/core": "2.4.3",
- "@docusaurus/preset-classic": "2.4.3",
+ "@docusaurus/core": "3.0.0",
+ "@docusaurus/preset-classic": "3.0.0",
// upgrade to MDX v3
- "@mdx-js/react": "^1.6.22",
+ "@mdx-js/react": "^3.0.0",
// upgrade to prism-react-renderer v2.0+
- "prism-react-renderer": "^1.3.5",
+ "prism-react-renderer": "^2.1.0",
// upgrade to React v18.0+
- "react": "^17.0.2",
- "react-dom": "^17.0.2"
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
},
"devDependencies": {
// upgrade Docusaurus dev dependencies to v3
- "@docusaurus/module-type-aliases": "2.4.3"
- "@docusaurus/types": "2.4.3"
+ "@docusaurus/module-type-aliases": "3.0.0"
+ "@docusaurus/types": "3.0.0"
}
"engines": {
// require Node.js 18.0+
- "node": ">=16.14"
+ "node": ">=18.0"
}
}
# 將新版本套件進行安裝
yarn install

有遇到的問題

Cause: Cannot find module 'prism-react-renderer/themes/github'

主要是在升級prism-react-renderer後, 匯入主題的用法有更新所導致的

// docusaurus.config.js
- const lightTheme = require('prism-react-renderer/themes/github');
- const darkTheme = require('prism-react-renderer/themes/dracula');
+ const {themes} = require('prism-react-renderer');
+ const lightTheme = themes.github;
+ const darkTheme = themes.dracula;

從v2開始預設包含的語言更少, 需要根據自己的需求添加

// docusaurus.config.js
const siteConfig = {
themeConfig: {
prism: {
additionalLanguages: ['bash', 'diff', 'json'],
},
},
};

結語

筆者用到的東西較少, 所以更新起來遇到的問題也不多, 但基本上官方文件其實寫的蠻清楚的, 如果有遇到錯誤不仿可以參考一下官方文件

參考資料

· 閱讀時間約 3 分鐘
junminhong(jasper)

問題

最近突然收到機器disk space使用量已滿的通知, 並造成服務暫時性停擺

趕緊進入機器排查, 發現mysql使用的磁碟量非常高, 但以目前資料量來說是不成正比的

根據排查結果發現mysql裡面有一個檔案佔用磁碟容量非常多

--- 可以使用這串SQL query查出目前佔用容量最大的file, 可以發現ibtmp1 file容量非常大
SELECT FILE_NAME, FILE_TYPE, TABLESPACE_NAME, (TOTAL_EXTENTS * EXTENT_SIZE) / 1024 / 1024 / 1024 AS 'total size(GB)'
FROM INFORMATION_SCHEMA.FILES
ORDER BY `total size(GB)` DESC;

找到問題後?

  • 首先進到mysql.cnf裡面新增
# 根據自己的需求設定最大限制要多少容量, 這邊則先設定20G
innodb_temp_data_file_path = ibtmp1:12M:autoextend:max:20G
  • 設定完成之後, 請將mysql進行重啟
# 重新啟動mysql service
sudo systemctl restart mysql.service
  • 查看設定是否有正確套用
-- 可以使用這串SQL query確認剛剛的設定有正確被套用
SHOW VARIABLES LIKE '%innodb_temp_data_file_path%';

-- 要能夠看到這個設定, 才代表你剛剛設定的東西有被套用
ibtmp1:12M:autoextend:max:20G

為什麼會這樣?

由於預設情況下, mysql會創建12MB的臨時表空間, 當如果今天某個操作創建出了20MB的臨時表空間, 這時候會自動擴展至20MB, 會自動回收資料, 但擴展後佔用的磁碟空間則不會自動回復至12MB

那這個時候可以透過設定最大擴展size或者重新啟動服務解決無限擴展的問題

可以怎麼預防?

  • 減少會使用到大空間臨時表的操作, 如: 複雜的查詢、排序、聯合查詢

參考資料

· 閱讀時間約 2 分鐘
junminhong(jasper)

為什麼需要安裝指定版的python

因為ubuntu16預設的python是3.5, 當今天需要安裝一些套件做編譯時, 會遇到版本過舊的問題

那要怎麼安裝呢?

方法一: PPA

# 更新安裝包列表
sudo apt-get update

# 安裝套件
sudo apt-get install software-properties-common

# 加入ppa:deadsnakes/ppa
add-apt-repository ppa:deadsnakes/ppa

# 更新安裝包列表
sudo apt-get update

# 直接透過apt-get安裝指定版本的python
sudo apt-get install python3.9

方法二: 自己的python自己編譯 😆

由於無法正常使用PPA直接安裝其他的python版本, 只好自己編譯了...

python的原始碼可以在這邊下載

# 取得python3.9.18壓縮包
wget -c https://www.python.org/ftp/python/3.9.18/Python-3.9.18.tgz

# 解壓縮
tar -zxvf Python-3.9.18.tgz

# 進入資料夾
cd Python-3.9.18

# 配置編譯環境
./configure --prefix=/usr/local/bin/[email protected]

# 編譯
make

# 安裝
sudo make install

# link, 將原本系統的python3連接到先編譯好的python3.9.18上
sudo ln -sf /usr/local/bin/[email protected]/bin/python3 /usr/bin/python3

# 查看python 版本
python3 -V

奉勸

os版本還是要記得升級啊, 免得新套件很多東西都沒有辦法正常編譯😭

· 閱讀時間約 1 分鐘
junminhong(jasper)

簡單幾步驟, 立即享有不同版本的docker-compose 🚀

# 下載docker-compose
# version, 根據自己的需求調整
sudo curl -L "https://github.com/docker/compose/releases/download/${version}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 改變權限
sudo chmod +x /usr/local/bin/docker-compose

# 查看docker-compose版本
docker-compose -v

· 閱讀時間約 6 分鐘
junminhong(jasper)

懶人包

# 使用fallocate 創建出一個4G的swapfile.1
sudo fallocate -l 4G /var/swapfile.1
# 更改檔案權限
sudo chmod 600 /var/swapfile.1
# 將檔案設置成swap file
sudo mkswap /var/swapfile.1
# 啟用記憶體交換空間
sudo swapon /var/swapfile.1

都出大事了, 還在慢慢看教學文章, 懶人包複製貼上, 直接搞定😆

先來個小劇場

原本都是用免費額度開一台不錯規格的GCE, 但最近在測試以最低成本也能夠運行服務, 所以將GCE規格改成「e2-micro」

當機器啟動完成後, 覺得服務應該都有正常開啟吧

所以我就下了一個魔法指令, 來看看目前的container是否都安好

docker ps

結果發現...怎麼有一個服務沒有被運行呢?然後想說手動重啟一下沒被運行的container

當開啟瀏覽器並打開服務後, 發現事情不是我想得這麼單純, 一直覺得奇怪怎麼無法連上呢???

然而我又回到GCE上再次輸入了神奇的指令後, 發現這次連docker運行資訊都不給我了, 整台機器直接當機!!

小劇場完來說說該如何解決吧

在小劇場中有提到多運行一個服務時會造成GCE當機, 經過多方面的排查後, 發現原來問題點出在記憶體身上

小訣竅!這邊可以使用這個指令去看每個container運行時大概會使用多少的記憶體

docker stats

因為「e2-micro」規格只有1G的記憶體, 但是其他服務已經將這個1G用的差不多了, 然而我又手動在啟動了一個服務

那這時候就會出現記憶體不足的現象導致整台GCE當機

解決方法

當確認完問題點後就來解決吧

這邊我會提供基本的兩個方法可以參考:

方法一 (土豪推薦)

如果你沒有任何的成本考量的話, 我非常建議你直接使用方法一, 你會省很多時間, 也是最簡單的解決方法😆

你只需要一個步驟, 將你的GCE的記憶體調大一點就可以輕鬆解決了 ~

方法二 (平民推薦)

練習時當然要學習控制成本以及將有限的資源最大化, 不然光機器成本就讓我月底吃土好像也不太對...

那方法二的解決思維就是透過比較便宜的硬碟去換取高價格的記憶體空間

因為我已經有將我的GCE空間調整至20G, 但其實我目前根本用不到這麼多, 但是因為硬碟只要往上加就沒辦法在往下調整了

所以我一直很煩惱到底要怎麼壓榨我剩餘的空間來達到成本最佳化

剛好遇到這個問題可以好好善用我閒餘的硬碟空間

創建一個4G的swap file

由於我的空閒硬碟空間蠻大的, 所以我這邊直接創建一個4G的swap file出來, 主要還是要以你自身的情況去評估要開多少的虛擬記憶體

這邊提供個簡單的計算方法: 實體記憶體 * 2 = 虛擬記憶體

sudo fallocate -l 4G /var/swapfile.1

設定檔案權限

為了安全性的問題, 這個檔案只能被root讀寫

sudo chmod 600 /var/swapfile.1

將檔案設置為記憶體交換空間

sudo mkswap /var/swapfile.1

啟用記憶體交換空間

sudo swapon /var/swapfile.1

查看記憶體交換空間

swapon -s

查看記憶體交換空間使用狀況

free -h

查看更詳細的記憶體資訊, 其中也有包含交換空間的資料

grep -i swap /proc/meminfo

設定開機自動掛載

vim /etc/fstab
# 加入這段
/swapfile swap swap defaults 0 0

查看記憶體交換空間優先度

數值範圍為0-100, 預設數值60, 越靠近0表示越避免使用記憶體交換, 反之相反

cat /proc/sys/vm/swappiness

修改記憶體交換空間優先度

sudo sysctl vm.swappiness=10

永久更改記憶體交換空間優先度

vim /etc/sysctl.conf
# 加入這段
vm.swappiness=10

刪除記憶體交換空間檔案

# 停用記憶體交換空間
sudo swapoff -v /var/swapfile.1
# 刪除檔案
sudo rm /var/swapfile.1