Somewhere I Belong

All about geek's life


  • 首頁

  • 開源專案

  • 關於

  • 歸檔

  • 標籤

Python 2.7 Threading / Queue 的 timeout 問題

發表於 4月 29 2016   |  

最近遇到一個很坑的問題…

那就是系統時間只要 倒退嚕 某些 Python thread 就會卡住 (其實不是卡住)

我們都知道系統時間是有可能會改變的 (藉由 NTP, 基地台校時, 手動, 等方式),但是很多程式的 timeout 相關機制設計是有缺陷的。舉個例子:一個 10 秒的 timeout 可以寫成 起始系統時間 - 現在系統時間 >= 10 就執行

淺而易見地,如果今天時間回溯如:2016 調整到 2000,那這樣這個 timeout 要等 16 年 才會觸發…

所以通常,有幾種做法:

  1. 使用 monotonic time

    The kernel call for time functions. Using CLOCK_MONOTONIC is typically better than using CLOCK_REALTIME because the monotonic clock is always increasing, so you don’t have to worry about someone’s changing the clock.
    ref: http://www.qnx.com/developers/docs/6.4.1/neutrino/technotes/time.html

  2. 取兩個時間相減後的絕對值 (缺點:並非真正的 timeout 時間,但可以抵抗系統時間往前。如果你沒辦法取得 monotonic time 也許也是一個方式)

在 Python 世界中,一直到 PEP 418 – Add monotonic time, performance counter, and process time functions,規範 stdlib monotonic time 的機制。(可能是考量到跨平台與可移植性…所以直到 2012 才加入這個功能)

Anyway, Python 2.7 中,Queue.get(), 以及 threading.condition 中都使用了 time.time() 來判斷 timeout,如此一來只要使用者不慎將時間往回調你的程式行為可能就不如預期。
(題外話:系統時間大幅度往前實際上是很少發生的,也應該要被避免。因為其他背景執行程式如何實作 timeout? 或是其他功能可能會有預期外的行為發生。)

可以看一下 Python 2.7 source code 其中的 _time() 是 time.time(),所以可以明顯地看出如果系統時間往回調,這邊的 threading.condition.wait() 會行為異常。

endtime = _time() + timeout
delay = 0.0005 # 500 us -> initial delay of 1 ms
while True:
gotit = waiter.acquire(0)
if gotit:
break
remaining = endtime - _time()
if remaining <= 0:
break
delay = min(delay * 2, remaining, .05)

以上取自 https://github.com/python/cpython/blob/2.7/Lib/threading.py#L349-L358

像這樣的例子在 Python code base 還有很多,詳細請見這個 patch 將所有 timeout 全部替換成使用 monotonic 來計算

  • patches: http://bugs.python.org/review/22043
  • issue: http://bugs.python.org/issue22043

最後補上一些前人的痛:

  • threading.Timer/timeouts break on change of win32 local time
  • [Python] Debug python 程式 hang 在 Queue.get() 的問題

最後我想說:Let’s upgrade to Python 3.5!

比對兩個資料夾下的檔並輸出彩色 diff

發表於 3月 24 2016   |  

平常都在 git repo 內做 diff,一時之間不知道要怎麼比對兩個資料夾底下的檔案

這邊作一下紀錄…

λ ~/temp/ diff -bur FOLDER_1 FOLDER_2

會發現輸出的 diff 居然沒有顏色…

於是乎又找到 colofdiff

直接 apt-get install colordiff 即可,就會變成這樣

diff -bur FOLDER_1 FOLDER_2 | colordiff

// 存起來
diff -bur FOLDER_1 FOLDER_2 | colordiff > your.diff

打完收工。

架設 tftp server 在 Ubuntu 環境

發表於 1月 3 2016   |  

TFTP (Trivial File Transfer Protocol),是很常見的通訊協議用在一些小系統上,如 cisco 韌體更新、或是有些廠家會 BIOS 內建 tftp 下載 rom 檔功能。如此輕巧簡易的通訊協議就很常派上用場。

Reference: How do I install and run a TFTP server?

  1. 先安裝好相關套件

    sudo apt-get install xinetd tftpd tftp
  2. 新增一組設定檔,放置於 /etc/xinetd.d/tftp

    service tftp
    {
    protocol = udp
    port = 69
    socket_type = dgram
    wait = yes
    user = nobody
    server = /usr/sbin/in.tftpd
    server_args = /tftpboot
    disable = no
    }

這邊可以看到開啟了 udp 在 69 port、user 是 nobody、server 是 /usr/sbin/in.tftpd、而帶入的參數即為我們放置檔案的資料夾 /tftpboot

  1. 新增 /tftpboot 資料夾,並且修改權限

    sudo mkdir /tftpboot
    sudo chmod -R 777 /tftpboot
    sudo chown -R nobody /tftpboot
  2. 將 xinetd 重新啟動

    sudo service xinetd restart
  3. 放置一任意檔案,然後用 tftp 測試

    tftp localhost
    tftp> get test
    Sent xxx bytes in 0.0 seconds

    tftp> quit

    cat test

大功告成,打完收工。

查看 Docker 每個 Container 流量 (使用 ip nets 指令)

發表於 1月 3 2016   |  

忘記是哪一天,忽然想檢查一下各別 Container 的流量用了多少,上網隨手找了一下,看到可以使用 ip-netns - process network namespace management 這個指令來查看不同 namespace 底下的流量。

具體方式如下:

  1. 取得 Container PID, 這邊我查看名為 wordpress_wordpress_1 的 container

    λ ~/docker inspect -f '{{ .State.Pid }}' wordpress_wordpress_1
    658
  2. 建立連結至 /var/run/netns/ 供 ip netns 使用

    λ ~/sudo ln -sf /proc/658/ns/net /var/run/netns/wordpress
  3. 利用 ip netns 接 iptables 流量就一目了然了!

    λ ~/sudo ip netns exec wordpress iptables -L -nv
    Chain INPUT (policy ACCEPT 639 packets, 106K bytes)
    pkts bytes target prot opt in out source destination

    Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
    pkts bytes target prot opt in out source destination

    Chain OUTPUT (policy ACCEPT 610 packets, 882K bytes)
    pkts bytes target prot opt in out source destination

Reference: Counting bandwidth from a Docker container

Rsyslog 設定順序是有差別的 (開啟 UDP bind 127.0.0.1)

發表於 1月 3 2016   |  

在設定 Rsyslog 時,預設 Debian 7 沒有打開 local udp 514 port 接收的功能。所我就簡單加入:

$ModLoad imudp
$UDPServerRun 514

後來發現,預設是 bind 在 0.0.0.0 相當之危險~等於所有人都可以打 log 到你機器上,於是我又再加入:

$ModLoad imudp
$UDPServerRun 514
$UDPServerAddress 127.0.0.1

發現沒有用,還是 bind 在 0.0.0.0,死馬當活馬醫…調整一下順序:

$ModLoad imudp
$UDPServerAddress 127.0.0.1
$UDPServerRun 514

這樣就可以了(暈),原來 Rsyslog 的設定順序是不可逆的。找個時間可以再深入研究一下…(遠目)

檢查一下 netstat -nlp | grep 514:

udp        0      0 127.0.0.1:514           0.0.0.0:*                           12274/rsyslogd

打完收工。

關閉 SSH SendENV 解決 locale 問題

發表於 1月 3 2016   |  

前幾天遇到一個詭異的問題,就是我使用 ssh 登入遠端 Server,執行特定程式會發生 locale 的問題,看了一下 locales…

驚人的事情發生了!因為同事電腦登入過去一樣下 locales 居然跟我的不一樣…這是什麼妖術?

原來,預設 ssh 會預設傳送本地端的 env 到遠端 server ,為了解決此問題只要編輯 /etc/ssh/ssh_config,把 SendEnv 這一行註解掉即可。

原本錯誤訊息可能長這樣:

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = (unset),
LC_ALL = (unset),
LC_PAPER = "de_DE.UTF-8",
LC_CTYPE = "de_DE@euro",
LANG = "en_US.UTF-8"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").

或這樣

locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory

reference: http://www.jerri.de/blog/archives/2009/12/04/problem_with_locales_on_remote_server_via_ssh/

Wireshark x ssh x tcpdump 遠端偵錯

發表於 12月 15 2015   |  

最近工作常常需要用到 Wireshark 來看看一些怪怪的問題…

如果是要除錯一般 ethernet 就還好,可以借一台具備 Port Mirror 功能的 Switch 來除錯,但是如果遇到像是 WiFi 或 Cellular 這種無線介面,就只能用 TCPDUMP 擋著…

但是,光是從 console 觀察 TCPDUMP 資訊實在很費工夫,好在 Wireshark 有提供從 stdin pipe 進來的機制 (當然,你也可以用 tcpdump 存成檔案在用 Wireshark 來讀取)

於是乎,只要下…

Linux / Mac

ssh -l root 192.168.3.127 tcpdump -U -s0 -w - -i eth1 | wireshark -k -i -

eth1 換成你要的介面

Windows (without cygwin)

plink.exe -ssh -pw abc123 root@192.168.2.1 "tcpdump -ni eth0 -s 0 -w - not port 22" | "C:\Program Files\Wireshark\Wireshark.exe" -k -i -

其中 plink 可前往 putty 下載頁面 Download

Reference:

  • Remote capture via ssh and pipe

依照檔名中版本號碼排序

發表於 11月 6 2015   |  

ls -v 可以依照檔名中的版本來排序,根本太強大啊!

Before -v

root@zack:/unstable# ls i-feel-so-good*.deb -alh

-rw-rw-r-- 1 zack zack 2.2M Sep 14 11:41 i-feel-so-good0.9.0_all.deb
-rw-rw-r-- 1 zack zack 1.7M Oct 13 17:40 i-feel-so-good0.9.10_all.deb
-rw-rw-r-- 1 zack zack 1.9M Oct 29 10:48 i-feel-so-good0.9.11_all.deb
-rw-rw-r-- 1 zack zack 1.8M Sep 22 17:25 i-feel-so-good0.9.1_all.deb
-rw-rw-r-- 1 zack zack 1.8M Sep 22 17:55 i-feel-so-good0.9.2_all.deb
-rw-rw-r-- 1 zack zack 1.8M Sep 24 15:28 i-feel-so-good0.9.3_all.deb
-rw-rw-r-- 1 zack zack 1.8M Sep 30 18:04 i-feel-so-good0.9.5_all.deb
-rw-rw-r-- 1 zack zack 1.8M Sep 30 18:41 i-feel-so-good0.9.6_all.deb
-rw-rw-r-- 1 zack zack 1.8M Oct 2 18:01 i-feel-so-good0.9.7_all.deb
-rw-rw-r-- 1 zack zack 1.7M Oct 13 10:17 i-feel-so-good0.9.8_all.deb
-rw-rw-r-- 1 zack zack 1.7M Oct 13 10:42 i-feel-so-good0.9.9_all.deb

After -v

root@zack:/unstable# ls i-feel-so-good*.deb -avlh
-rw-rw-r-- 1 apt-server apt-server 2.2M Sep 14 11:41 i-feel-so-good0.9.0_all.deb
-rw-rw-r-- 1 apt-server apt-server 1.8M Sep 22 17:25 i-feel-so-good0.9.1_all.deb
-rw-rw-r-- 1 apt-server apt-server 1.8M Sep 22 17:55 i-feel-so-good0.9.2_all.deb
-rw-rw-r-- 1 apt-server apt-server 1.8M Sep 24 15:28 i-feel-so-good0.9.3_all.deb
-rw-rw-r-- 1 apt-server apt-server 1.8M Sep 30 18:04 i-feel-so-good0.9.5_all.deb
-rw-rw-r-- 1 apt-server apt-server 1.8M Sep 30 18:41 i-feel-so-good0.9.6_all.deb
-rw-rw-r-- 1 apt-server apt-server 1.8M Oct 2 18:01 i-feel-so-good0.9.7_all.deb
-rw-rw-r-- 1 apt-server apt-server 1.7M Oct 13 10:17 i-feel-so-good0.9.8_all.deb
-rw-rw-r-- 1 apt-server apt-server 1.7M Oct 13 10:42 i-feel-so-good0.9.9_all.deb
-rw-rw-r-- 1 apt-server apt-server 1.7M Oct 13 17:40 i-feel-so-good0.9.10_all.deb
-rw-rw-r-- 1 apt-server apt-server 1.9M Oct 29 10:48 i-feel-so-good0.9.11_all.deb

又學到一招了!

秒建 WordPress 在你閒置的 Raspberry Pi 上

發表於 11月 1 2015   |  

最近把吃喝玩樂 Blog 從 Blogspot 搬到 WordPress 了!於是乎就想要玩玩各種功能…

Production 環境目前是 host 在 DigitalOcean ,看了旁邊的 Raspberry Pi 一眼好像閒著也是閒著,於是上網看看有沒有現成的 Docker Image 可以用,結果找不到喜歡的。就自己 Build 一個吧!

英文說明與 Dockerfile, Scripts 都在 Github 連結:imZack/wordpress-armhf

這邊主要會用到兩個 Image 分別是 zack/wordpress-armhf:4.3.1-apache 與 armbuilds/mariadb,詳細的 Dockerfile 可以在上面 Github 連結裡面找到。由於 Docker Hub 無法自動 Build armhf 的 Image 所以我必須先在 Raspberry Pi 上 build 好然後再推上去。(另有用 QEMU 方式,這邊先不多提…)

wordpress:
image: zack/wordpress-armhf:4.3.1-apache
restart: always
links:
- mysql
environment:
- WORDPRESS_DB_PASSWORD=wordpressmeetsdocker
ports:
- "8080:80"
volumes:
- ./www-data:/var/www/html

mysql:
image: armbuilds/mariadb
restart: always
volumes:
- ./mysql-data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=wordpressmeetsdocker
- MYSQL_DATABASE=wordpress

用上面的 docker-compose.yml 就能在幾秒內建立一個全新的 WordPress 環境囉!

只需要下 docker-compose up 等他跑完初始化,就能開啟 http://localhost:8080 Port 囉 !

淺讀 Netfilter Framework

發表於 10月 29 2015   |  

Background

  • Linux 2.3.x 時期 Paul Rusty Russel 寫的
  • 基本上就是插入一些 Hooks 到 Kernel module
  • Iptables 常常跟 Netfilter Framework 搞混,Iptables 屬於 Netfilter Framework 的一員

Hooks and The Callback Functions

有五種 Hooks 會插入在 Linux networking stack 中的不同階段

--> PREROUTING ---> [ROUTE] ---> FORWARD -------------------> POSTROUTING -->
| ^
| |
| [ROUTE]
V |
LOCAL IN ---> LOCAL PROCESS --> LOCAL OUT
閱讀全文 »
12…7
YuLun Shih

YuLun Shih

66 文章
6 分類
122 標籤
RSS
Creative Commons
© 2016 YuLun Shih
由 Hexo 強力驅動
主題 - NexT.Mist