5 月 30 2019
Toshiba KXG6AZNV512G on Lenovo T590
Toshiba KXG6AZNV512G 是 M.2 2280 規格的 NVMe SSD;官網可以查得 XG6 Series 產品資訊頁。
5 月 30 2019
Toshiba KXG6AZNV512G 是 M.2 2280 規格的 NVMe SSD;官網可以查得 XG6 Series 產品資訊頁。
5 月 26 2019
這幾個月前後經手處理兩個 HTTP 壓縮相關的問題,寫個紀錄…
第一個問題跟 ProgressEvent 有關。
敝單位有個 PWA ( Progressive Web Application ),幾個月前釋出一個新模組,讓 user 可獲取公司內部發佈的公告訊息。考量到訊息內容長度與行動裝置所在網路環境,我們便試著在訊息載入時加上進度條 (Progress Bar)。
實作期間,我們發現只能取得 ProgressEvent.loaded,抓不出 ProgressEvent.total,而且這個現象僅發生在 server response,瀏覽器發出請求/上傳檔案無此狀況。
確認這現象跟 HTTP 壓縮有關後,我們也發現 ProgressEvent.loaded 的值是未壓縮前的大小。
目前我們採用的解法是在讀取內容前先發個 HTTP request 取得內容長度,用該值取代 ProgressEvent.total。
第二個問題被發現時,我們正在調整 Cache-Control 設定;而且這問題只跟 Apache HTTPD 有關。
我們讓 HTTP server 壓縮 .js , .css , .htm 這類固定文字檔,也加上這串 HTTP header :
Cache-Control: public, max-age=86400, no-cache
但我們發現瀏覽器在 nginx 可正確獲得 304 Not Modified,但遇上 Apache HTTPD 永遠都是 200 OK。
花一堆時間測試/追蹤後發現兇手是 mod_deflate;原因是檔案被壓縮處理後,傳給瀏覽器的 HTTP ETag 後面被加上 “-gzip” 這串後綴。
目前的解法是參考這篇,用下面這段設定處理 .js , .css , .htm 這類固定文字檔的 Cache-Control:
RequestHeader edit "If-None-Match" "^\"(.*)-gzip\"$" "\"$1\"" Header edit "ETag" "^\"(.*[^g][^z][^i][^p])\"$" "\"$1-gzip\""
Apache HTTPD 2.5 版的 mod_deflate 應該會多個 DeflateAlterETag 供作調整;等吧…
4 月 7 2019
3 月 16 2018
2016 年自己寫過 改用 Let’s Encrypt 的 certificates,文內提到的 dehydrated 也持續在使用。
這幾天看到 Let’s Encrypt 貼出 ACME v2 and Wildcard Certificate Support is Live。
Let’s Encrypt 的 wildcard certificate 實作大概要注意以下幾點:
使用 dehydrated 進行 DNS challenge 可以參考這幾份文件:
我選擇用 nsupdate 的方式(參考 dehydrated Wiki : example dns 01 nsupdate script),在 DNS master server 建立 _acme-challenge.{DOMAIN} 的 NS record,讓 hook script 透過 nsupdate 連線到指定的 name server 更新 TXT record 。
DNS 方面完成後,要記得佈署 hook script 與 nsupdate 使用的 key。
接著是調整語法,原本的語法:
/SOMEWHERE/dehydrated/dehydrated -c -d {網站hostname}
改為:
/SOMEWHERE/dehydrated/dehydrated \ -c -d *.{DOMAIN} \ -t dns-01 -k {HOOK_SCRIPT} \ --alias wildcard.{DOMAIN}
( –alias 指定的 wildcard.{DOMAIN} 會成為目錄名稱,用來存放憑證 )
12 月 4 2017
再來還些債…
前陣子我們家在看一些 PHP 的版本差異,也順便拆一些地雷。
先說記憶體耗用,我們用下面這段程式在一些 PHP 版本上執行,觀察記憶體耗用:
<?php $a = memory_get_usage(); echo "begin:\t$a" . PHP_EOL; $arr = array(); for ( $i = 0; $i < 100000; $i++ ) { array_push($arr, $i); } $b = memory_get_usage(); echo "end:\t$b" . PHP_EOL; echo "diff:\t" . ($b - $a) . PHP_EOL;
在 PHP 5.1 ( on 32-bit Linux ) 觀察到的記憶體差距值大約是 5.8 MB,在 PHP 5.3 ~ 5.6 ( on 64-bit Linux ) 觀察到的記憶體差距值大約是 14 MB,而 PHP 7.1 ~ 7.2 ( on 64-bit Linux ) 觀察到的記憶體差距值大約是 4 MB。
至於 PHP 的 MySQL driver/library 方面…
參考官方提供的 Overview of the MySQL PHP drivers : Buffered and Unbuffered queries ;PHP 的所有的 MySQL extensions 預設使用 buffered mode,所以在撈取大量資料時,PHP 執行完 SQL statement 就會耗用大量記憶體。
另外,在官方提供的 Overview of the MySQL PHP drivers : Choosing a library 可以看到,PHP 5.3 以前的預設 MySQL driver ( libmysqlclient ) 沒使用 PHP 的原生記憶體管理,PHP 5.3 之後的預設 MySQL driver ( mysqlnd; MySQL Native Driver) 才開始用。
對這些行為,我們另外生了一段測試程式:
<?php $a = memory_get_usage(); echo "begin:\t\t$a" . PHP_EOL; $dbConn = new PDO(.....); $b = memory_get_usage(); echo "new PdoMySQL:\t$b\t\tDiff: " . ($b - $a) . PHP_EOL; $st = $dbConn->query("SELECT * FROM testTable LIMIT 30000"); $b = memory_get_usage(); echo "get Stmt:\t$b\tDiff: " . ($b - $a) . PHP_EOL; $row1 = $st->fetch(); $b = memory_get_usage(); echo "fetch once:\t$b\tDiff: " . ($b - $a) . PHP_EOL; $row2 = $st->fetch(); $b = memory_get_usage(); echo "fetch twice:\t$b\tDiff: " . ($b - $a) . PHP_EOL; $st->closeCursor(); $b = memory_get_usage(); echo "closeCursor:\t$b\t\tDiff: " . ($b - $a) . PHP_EOL; $row3 = $st->fetch(); $b = memory_get_usage(); echo "fetch:\t\t$b\t\tDiff: " . ($b - $a) . PHP_EOL; var_dump($row3);
在 PHP 7.1 ( with mysqlnd , 64-bit Linux ) 的數據如下:
begin: 355552 new PdoMySQL: 378784 Diff: 23232 get Stmt: 25866944 Diff: 25511392 fetch once: 25868752 Diff: 25513200 fetch twice: 25870568 Diff: 25515016 closeCursor: 384104 Diff: 28552 fetch: 384104 Diff: 28552 bool(false)
在 PHP 5.1 ( with libmysqlclient , 32-bit Linux ) 的數據則是:
begin: 50432 new PdoMySQL: 85752 Diff: 35320 get Stmt: 92184 Diff: 41752 fetch once: 93584 Diff: 43152 fetch twice: 95248 Diff: 44816 closeCursor: 95312 Diff: 44880 fetch: 95400 Diff: 44968 bool(false)
應該有為數不少的 PHP developers 曾經踩過這種記憶體相關的地雷…
11 月 30 2017
之前曾經使用 PHPExcel 踩到地雷,處理完之後一直忘記載這邊留個紀錄(拖稿?)。
Excel 的活頁簿標題有字元 & 長度限制,但 library ( PHPExcel ) 沒有特別判斷 & 處理,所以…
// Excel 的活頁簿 title 不允許 * : / \ ? [ ] $currTitle = str_replace( array('*', ':', '/', '\\', '?', '[', ']'), "", $currTitle ); // 字數上限 31,保守抓 30 $maxByte = 90; $chars = mb_strlen($currTitle, 'UTF-8'); while ( $chars > 30 ) { $currTitle = mb_strcut($currTitle, 0, $maxByte, 'UTF-8'); $chars = mb_strlen($currTitle, 'UTF-8'); $maxByte--; }
2 月 22 2016
之前都在用 StartSSL 的免費 certificate,雖知道有 Let’s Encrypt,但因手邊幾乎都轉用 nginx,遲遲沒下手。
約莫一週前 zeroplex 丟了這個網頁:「Why I stopped using StartSSL (Hint: it involves a Chinese company)」,三、四天前 DK 大神也撰文提及,就決定趁週末沒什麼事來動工…
用 DK 大神在一個月前撰文提過的 dehydrated 這個 GitHub 專案可以輕鬆搞定,步驟大致如下…
mkdir dehydrated/.acme-challenges
dehydrated/dehydrated -c -d {網站hostname}
server { listen 443 ssl http2; listen [::]:443 ssl http2; ssl on; ssl_certificate /SOMEWHERE/dehydrated/certs/{網站hostname}/fullchain.pem; ssl_certificate_key /SOMEWHERE/dehydrated/certs/{網站hostname}/privkey.pem; ssl_trusted_certificate /SOMEWHERE/dehydrated/certs/{網站hostname}/fullchain.pem; .... }
我記得 Let’s Encrypt 的 certificate 要在 90 天內 renew,所以 cron job 這樣放:
0 0 1 */2 * /SOMEWHERE/dehydrated/letsencrypt.sh -c -d {網站hostname} > /dev/null 2>&1
Updated : letsencrypt.sh 改為 dehydrated 。
12 月 10 2015
以往的網頁純粹就是 HTML,之後的動態網頁技術 ( CGI、PHP、ASP、JSP、… )、CSS、VBScript、Javascript 雖讓網頁內容/效果愈來愈多元,網頁開發/維護難度的關鍵亦僅取決於語言的熟悉度。
近幾年則是冒出了不少網頁前端 frameworks。 node.js、io.js 與 React、Angular、Backbone、Ember、…,雖說是使用相同的程式語言,但各種 frameworks 的選用與導入著實讓不少網頁前端開發人員頭疼。
考量多螢、多裝置的兼容性, COSCOP 2015 就有人提出 “每18至24個月,前端技術的難度會增加一倍以上”。
但… 真只有網頁前端開發人員的日子愈來愈難熬嗎?
SQL Injection、XSS、CORS 等議題與考量呢?
我個人一直認為程式語言只是工具,沒特別去吹捧某特定程式語言;同理,我也把 frameworks 當作是工具。
我們看到的一些新技術/framework 固然很好,真有立即導入的必要性嗎?
若看到新的技術屏除跟風心態,先稍作觀望,讓環境的變化幫我們除強汰弱,另一方面加強人員的教育訓練,新技術導入前仔細評估,審慎抉擇,是否網頁開發人員就可以不必過得如此辛苦?
8 月 25 2015
前陣子調整了一些 Apache HTTPD & Tomcat & nginx 的 cache 機制與內容壓縮機制,稍微紀錄一下。
Apache HTTPD 的 cache:
<IfModule mod_expires.c> ExpiresActive On ExpiresByType image/gif "access plus 1 month" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType image/png "access plus 1 month" ExpiresByType text/css "access plus 1 month" </IfModule>
Apache HTTPD 的壓縮:
<IfModule mod_deflate.c> DeflateCompressionLevel 9 AddOutputFilterByType DEFLATE text/html text/plain text/xml application/x-httpd-php AddOutputFilter DEFLATE js css </IfModule>
Apache Tomcat 的 cache(在 application 的 web.xml 做調整):
<filter> <filter-name>ExpiresFilter</filter-name> <filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class> <init-param> <param-name>ExpiresByType image</param-name> <param-value>access plus 1 month</param-value> </init-param> <init-param> <param-name>ExpiresByType text/css</param-name> <param-value>access plus 1 month</param-value> </init-param> <init-param> <param-name>ExpiresByType application/javascript</param-name> <param-value>access plus 1 month</param-value> </init-param> </filter> <filter-mapping> <filter-name>ExpiresFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> </filter-mapping>
Apache Tomcat 的壓縮(在 conf/server.xml 做調整):
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" compression="on" compressableMimeType="text/html,text/xml,text/plain,text/css,application/javascript" redirectPort="8443" />
nginx 的 cache(在 server tag 內做調整):
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { expires 1M; }
nginx 的壓縮(在 http tag 內做調整):
gzip_vary on; gzip_proxied any; gzip_comp_level 9; gzip_buffers 8 32k; gzip_http_version 1.0; gzip_types text/plain text/css application/json application/javascript application/x-javascript text/javascript text/xml application/xml application/rss+xml application/atom+xml application/rdf+xml;
大概就調這些,其他多媒體檔案就看需求了…
7 月 24 2019
Logstash 筆記
為了分析某些儲存在 MySQL 的 log,敝單位在兩年前(2017)導入 Logstash;當時我們用最新的 5.5.1 版,運作狀況還不錯,所以就沒什麼人理它…
最近冒出問題,救完火後寫個紀錄。
第一個問題是這個:
資料的第一個欄位是 auto-increment 的 ID,看到 ‘2.147483727E9’ 就聯想到是 32 位元正整數溢位問題。
我們先換 MySQL Connector/J (& 改用 OpenJDK);換完之後,看到的錯誤訊息變成這樣:
於是我們就開始升版 Logstash;目前最新的版本是 7.2.0,但 官方的 migration guide 說要先升版到 6.7。
最後我們順利升上 7.2.0,在過程中也發現 6.7.2 已無 32 位元正整數溢位問題。
第二個問題發生在升版後:
)
DATETIME 欄位存放的 ‘2019-07-23 14:18:59’ 抓成 ‘2019-07-23T19:18:59.000Z’。
沒人能保證系統/伺服器會跨多少時區,為免夜長夢多,我們的解決方式是轉成 UNIX timestamp。
(Year 2038 problem? 以後再說!
By Joe Horn • Computer Software 0 • Tags: JDBC, Logstash, MySQL