Vespa 在處理查詢的時候,有預設的 timeout 機制,能夠在時間不夠的時候將既有已經收集到的結果吐出,而不是放棄既有的結果並回覆 504 timeout。這樣的行為其實就是現代的 reactive system 的思維。這裡會簡要地介紹 timeout 的機制 [1],並且提一下最近遇到的實例。
Software entities (class, modules, functions, etc.) should be open for extension, but closed for modification. Junior programmers create simple solutions to simple problems. Senior programmers create complex solutions to complex problems. Great programmers find simple solutions to complex problems. 註1:本部落格的範例程式碼在 2015 年以前的文章中,大多是以全型空白做縮排。如需服用,請自行用文字編輯器的取代功能把全型空白取代成半型空白。
- Bertrand Meyer
- Charles Connell
註2:本部落格的內容授權請參閱部落格底部的授權宣告。
2022年4月9日 星期六
2022年2月21日 星期一
S3 檔案不存在時有可能會拿到 403 錯誤
筆記,原來 S3 要檢查檔案是否存在,是需要有 s3:ListBucket 的權限的,如果沒有這個權限的話,當檔案不存在時 S3 會拋出的錯誤會是 403 而不是 404,代表的是 S3 想要 list bucket 但沒有足夠權限…。
參考資料
2022年2月20日 星期日
JMeter 自訂輸出結果
JMeter 預設的套件能夠根據測試對象輸出像是 throughput、latency、status code 等數據的報告,不過如果遇到自己想輸出的東西是從 API response 裡萃取出來的狀況,就會稍微麻煩一點。實際上還是能夠做到,但看起來會存在一些限制,這篇會簡單紀錄一下需要做的事情。
使用 sample variables 自訂變數
JMeter 有個 sample_variables 的參數,在啟動測試時可以一起帶進去指定,JMeter 在最後輸出 JTL 時就會一起把 sample_variables 裡指定的變數一起輸出到 JTL 裡。
jmeter -Jsample_variables=price -n -t mytest.jmx -l test_result.csv
以上述的指令來說,指定的自訂變數就是 price 這個變數,只要在測試過程當中有把結果寫入到 price 變數,JMeter 在寫入 JTL 時就會把 price 一起寫進去了。輸出的結果會類似這樣:
timeStamp,elapsed,label,responseCode,responseMessage,threadName,dataType,success,failureMessage,bytes,sentBytes,grpThreads,allThreads,URL,Latency,IdleTime,Connect,"price" 1645111313217,1292,Random Commerce Request,200,OK,Thread Group 1-6,text,true,,946,150,10,10,https://random-data-api.com/api/commerce/random_commerce,1285,0,1010,65.85
可以看到最後面多了一個 “price” 的欄位。
產生自訂變數的報告
這個看起來存在一些限制,本來我希望的結果是產生像是 aggregate report 那樣的表格,可以幫我計算自訂變數的平均數、標準差、中位數、百分位數等等的。但目前看起來好像只能夠讓 JMeter 在產生 HTML 報告的時候引入自訂變數而已,而且報告產生的樣式似乎也沒什麼可調整的空間?不知道有沒有其他 plugin 可以協助,不過目前是沒有找到…。
這裡單純紀錄一下,產生報告的時候目前不能用 Java 17,會噴出錯誤訊息。可以換成 Java 8 或 11。
參考資料
2022年2月5日 星期六
準備 Vespa 測試環境
其實本來想紀錄一下建 Vespa container 的過程,但翻了一下之前的文章 [1],發現其實雖然細節有點不同,但大體上也是大同小異,這篇就簡單寫了,畢竟內容其實就跟 Vespa 的 Github 上寫得差不多 😆。
這篇其實算是個前置作業,目的是因為最近想紀錄一點 Vespa 的實驗數據,不過畢竟不能拿公司的數據放部落格(其實也不是公司不允許,單純只是要申請跟審核感覺很麻煩,我懶得弄 🙈),所以想要用簡單的 Vespa container 來做測試。基於這個原因,需要在自己的電腦準備一個 Vespa 環境,並且需要塞一些合理的測試資料進去。Vespa 團隊在他們的 Github [2] 上有準備一個 e-commerce 的範例,看起來還不錯,所以預計會先拿這個來做初始環境的建置。
2022年1月25日 星期二
Vespa 的新功能 hash dictionary
在翻閱 Vespa 的部落格 [1] 時,看到在 2021 年 5 月時,Vespa 新增了 hash dictionary 的功能,所以就來紀錄一下這個功能的細節。
hash dictionary 是什麼?
在 Vespa 的設計中,當欄位被設定為 attribute 時,可以另外加上 fast-search 的設定,讓 Vespa 自動幫這個欄位建立 index 以加快搜尋速度。原本 Vespa 的 fast-search 只能夠使用 b-tree 的資料結構來建立,但現在我們可以選擇使用 hash table 的資料結構來建立 index,在特殊的情境下能夠獲得比 b-tree 更好一點的效能。
hash dictionary 的限制
目前測試發現 hash dictionary 需要設定為 cased,而且必須要同時在 dictionary 跟 match 兩個設定上都加上 cased 才能通過檢查。不過這點我覺得在文件 [2] 上並沒有很明確地點出…。
field id type string {
indexing: summary | attribute
attribute: fast-search
dictionary {
hash
cased
}
match: cased
}hash dictionary 的效果
要比較效果的話,首先需要先看一下它的比較對象,也就是預設的 btree dictionary。對工程師來說,看到 b-tree 跟 hash 兩個關鍵字,應該大概就知道差別是什麼了!簡要來說就是 O(logn) 跟 O(1) 的差別 XD。不過除此之外,由於上述的 hash dictionary 的限制,在 Vespa 上設定 hash dictionary 還會另外衍生出 case-sensitive 的議題需要考慮。
首先先看一下 btree 的狀況,如果使用以下的設定的話,btree 的預設行為是 uncased,意味著 "bear" = "BEAR" = "Bear"。
field id type string {
indexing: summary | attribute
attribute: fast-search
}實際使用 [3] 建立出來的測試環境來測試的話,裡面有一個 asin: "B00GQ22Y6Y" 的 document,內容長這樣:
{
"pathId": "/document/v1/item/item/docid/B00GQ22Y6Y",
"id": "id:item:item::B00GQ22Y6Y",
"fields": {
"title": "Trendy Style Hand-knit Warm Lining inside Winter Bucket Hat w. Cute Flower-Purple #H01",
"asin": "B00GQ22Y6Y",
...(skipped)...
}
}此時用以下兩個 YQL 都能夠查到這個 document。這主要是因為預設的設定是 uncased,因此不管大小寫都可以順利查到結果。
SELECT * FROM item WHERE asin contains "b00gq22y6y"; SELECT * FROM item WHERE asin contains "B00GQ22Y6Y";
不過由於使用 hash dictionary 時,會需要設定 cased 屬性,導致更換成以下的 hash dictionary 時,狀況就會不太一樣了:
field id type string {
indexing: summary | attribute
attribute: fast-search
dictionary {
hash
cased
}
match: cased
}這時其實結果是 asin contains "b00gq22y6y" 可以查到資料,但 asin contains "B00GQ22Y6Y" 反而查不到…。這結果其實蠻出乎我的意料,不知道是不是 bug 或者是使用方式不正確之類的。
參考資料
Gradle 的 ‘plugin’ 區塊限制
很緩慢地直到去年年底才開始摸 Gradle,然後最近要試著自己弄小專案時,撞到一個奇怪的問題。我用 Gradle init 的指令幫忙產生第一版的 Gradle 設定,接著在根目錄的 settings.gradle 想要加入 java plugin,例如下面這樣:
plugins {
id "java"
}
repositories {
mavenCentral()
}
rootProject.name = 'sample-vespa-data-feeder'
include('app')結果意外地(我很意外 XD…)遇到了以下的錯誤訊息:
An exception occurred applying plugin request [id: 'java']
> Failed to apply plugin 'org.gradle.java'.
> Could not create plugin of type 'JavaPlugin'.
> Unable to determine constructor argument #3: missing parameter of type JvmPluginServices, or no service of type JvmPluginServices.結果到處亂看的時候,看到 [1] 才赫然發現,原來 plugin 是新的用法,而且這個用法好像不能寫在 root project 上。後來我把 plugins {} 跟 repositories {} 都改放進 app/build.gradle 就正常了….。
BTW,小小的題外話,我用 Gradle init 產生設定時,是選擇 single project 的,不過它產生出來的還是具有 multi project 的結構,總覺得 Gradle 的設計是不是其實根本沒有 single project….?
參考資料
2022年1月4日 星期二
[書籤] 阿里技术专家详解DDD系列
是說中國的文章最讓人困擾的地方,就是轉錄文章都不用記載的,所以超難分辨到底哪個才是原作者發的…。這裡單純只留我覺得比較容易閱讀的連結。不過第五篇是直接連接到可能是源出處的地方,因為轉錄的網站好像還沒收錄到它。(但我覺得轉錄的網站把排版排得比較易讀 XD)
2021年9月24日 星期五
Vespa 不能接受的 unicodes
筆記,Vespa 不能接受 /u0000 ~ /u001F 這些 unicodes,如果寫入的文字有包含他們的話,會得到下列的錯誤訊息。
The string field value contains illegal code point 0x0
2021年9月19日 星期日
在 Windows 建立 Ubuntu 與 Docker 環境:透過 WSL 2
之前有安裝過 WSL(Windows Subsystem for Linux),不過沒怎麼認真地玩過細節。主要還是會想在 Windows 上建立 Docker 的環境,但之前的痛點是在於 Docker Desktop for Windows 原本的作法是要建立在 Hyper-V 之上,也就是會透過在 Hyper-V 上開 VM 的形式來達成建立 container,這效能實在是有點略差。最近看到 Docker Desktop 似乎可以改用 WSL 2 來建立 container,另外又看到有 Windows Terminal 這個東西,看起來可以在 Windows 上弄出很接近 Linux 的環境,所以就想說來試一下這個!
2021年7月18日 星期日
Vespa weighted set
Vespa 有個 weightedset 的型態,我個人其實覺得 Vespa 的文件在針對 weightedset 的描述有點難懂,所以這邊會用範例來整理一下 weightedset 的實際效果。