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,而且必須要同時在 dictionarymatch 兩個設定上都加上 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 或者是使用方式不正確之類的。

參考資料
  1. Vespa Product Updates, May 2021
  2. Schema Reference – dictionary
  3. 準備 Vespa 測試環境

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….?

參考資料
  1. What the difference in applying gradle plugin

2022年1月4日 星期二

[書籤] 阿里技术专家详解DDD系列

是說中國的文章最讓人困擾的地方,就是轉錄文章都不用記載的,所以超難分辨到底哪個才是原作者發的…。這裡單純只留我覺得比較容易閱讀的連結。不過第五篇是直接連接到可能是源出處的地方,因為轉錄的網站好像還沒收錄到它。(但我覺得轉錄的網站把排版排得比較易讀 XD)

  1. Domain Primitive
  2. 第二弹 - 应用架构
  3. 第三讲 - Repository模式
  4. 第四讲:领域层设计规范
  5. 第五讲:聊聊如何避免写流水账代码

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 的實際效果。

2021年7月8日 星期四

Splunk 小基礎

覺得好久沒有寫部落格了 XD。今年工作上遇到許多意外,比原本預期的還要忙上許多;而且有不少想寫成文章的主題,其實都得思考到底能不能寫 XD;不過最重要的原因大概是因為開始在用 Notion 來做紀錄了吧。本來寫部落格的用意,就是用來紀錄遇到過的經驗,避免自己忘記了就消失了。不過在開始用 Notion 以後,總想說先把摘要紀錄在 Notion 上,之後再整理成文章,然後就....就沒有然後了,那些東西就一直維持摘要的樣子存在 Notion 上了 😂。

因為今天學到了一點關於 Splunk 的蠢事,所以來寫篇小文章,順便讓部落格添添火 (?

2021年4月25日 星期日

Java 11 的 HashMap

在 Java 中,HashMap 是個挺常用的 Map 類別的實作。而且嚴格來說,雖然 Map 在 JDK 中就有 HashMap 和 TreeMap 兩大類(其實還有其他像是 Property 啦,但我個人覺得不太會把他們放在一起討論 XD),不過其實大多數狀況大家需要用到 Map 時,都不是太在乎 Map 是否有多餘的特性,只在乎 Map 這個介面原本提供的特性,也就是「任意一個 key 在 Map 中都是唯一的」,所以相較於 TreeMap 來說,HashMap 是比較常被使用的類別。這篇文章就是要來討論一下 Java 11 的 HashMap。

會想要寫這篇文章,其實是最近開始在準備面試,然後翻到以前寫的文章提到 HashMap 的時間複雜度的問題,才突然想起 HashMap 有個奇妙的特性!同時當時查資料時的對象是 Java 7/8,但現在的主流已經是 Java 11 了,也有些好奇 Java 11 的 HashMap 是否有其他的變化,因此就花了些時間再來閱讀一下 Java 11 的 HashMap 實作了(雖然 Java 17 LTS 也快出了....)。

2021年3月30日 星期二

JMeter 的 QPS 上不去

紀錄一下最近用 JMeter 做效能測試時遇到的小問題。

之前本來在測試效能時,因為會在測試環境進行,測試環境一般規模會比較小,所以相對地效能測試時打的流量也會比較少,大概都是打個 100~200 QPS 而已。不過這次遇到比較不一樣的狀況,我們需要在線上環境做測試,而且流量想要打高一點,結果就遇到 QPS 沒辦法往上拉的問題。

首先,測試的 script 裡設定的 Thread Group 是 1,000 個 thread,並且會用 Throughput Shaping Timer 來調整實際打出去的流量。script 跑在 AWS 上,使用的 VM 規格是 m5a.2xlarge。在 QPS ~300 左右時都還沒什麼問題,不過一往上拉到 350 QPS 以上時,就會開始出現 JMeter 顯示 response time 大幅地增加,但從 API 端觀察則看不出存在門檻,而且實際上我們日常的流量超過 350 QPS 很多…。

由於這個反應不太合理,畢竟我們平常實際運行的流量都高於 350 QPS,沒道理跑 350 QPS 的測試會卡住,更何況從 API monitoring 那邊觀察起來,API 的 response time 也很正常,並沒有如 JMeter 顯示的突然上升超過 20 倍,因此這時就開始懷疑有可能問題是出在 JMeter 這邊,像是來不及處理 response 之類的問題了。

接連做了幾個實驗、並且同時觀察 CPU 使用率後,發現一旦 QPS 超過 350 時,CPU 使用率會停留在大約 70% 左右的位置,這時多半 response time 會開始顯著地上升。因此初步認為有可能是 CPU 造成效能卡住了,而結果也確實是如此。在我把 VM 規格改為 CPU-intensive 的 c5a.2xlarge 之後,問題解決了,QPS 可以繼續往上增加,撞到了下一個門檻是大概 QPS 550…。

QPS 550 的這個門檻,觀察 CPU 使用率約莫是落在 50%~60%,看起來不太像是問題所在,因此又開始朝別的方向思考。CPU 不對的話,下一個可能就是記憶體了。此時觀察 top 顯示的整體記憶體使用率只有 2GB 出頭,但我的 c5a.2xlarge 應該有 16GB 可以使用才對,同時查到 JMeter 文件顯示預設的 heap size 是 1GB….。嗯~那就來調整 heap size 看看吧。

在 JMeter 資料夾中的 bin/jmeter 檔案裡,搜尋 HEAP 可以找到下面這一段描述:

# This is the base heap size -- you may increase or decrease it to fit your
# system's memory availability:
: "${HEAP:="-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m"}"

這裡顯示預設的 -Xms 和 -Xmx 都是 1GB,把它調大成想要的樣子,例如最少 8GB、最多 15GB,如下所示:

# This is the base heap size -- you may increase or decrease it to fit your
# system's memory availability:
: "${HEAP:="-Xms8g -Xmx15g -XX:MaxMetaspaceSize=256m"}"

然後~門檻就消失了,後續就順利地繼續把 QPS 往上拉到 1K 以上了。

2021年2月20日 星期六

智慧家庭中樞 Hubitat 入門:安裝與 Mobile App

去年感恩節的時候,趁著 Amazon 國際運費免運的優惠,買了一台智慧家庭的 hub。本來研究了一段時間是想買 Samsung SmartThings Hub 的,不過因為搞不懂版本的差異以及剛好又沒貨(那時正好因為 COVID-19 國際貨運運量低迷,可能也有關係吧),所以最後在搜尋了一些國外的評論後,改買了 Hubitat Elevation。


圖片節錄自 Hubitat 官網 [1]