長距離的 WiFi 科技 (背景:烏克蘭網路)

Hacker News 上的「Ask HN: What's with the DIY state of the art long-range Wi-Fi?」這篇開頭,嘗試找出低成本且 scalable 的方式重建戰爭時期烏克蘭的網路。

發文的人想要透過一般民用的 WiFi 設備達到長距離 (這邊指的是遠超過 WiFi 設計時的距離,5~20km),但不用很快的網路 (大概 0.1~1Mbps):

The idea is to make a single device that can act as both a relay station, as well as an actual hotspot, it then can be placed in line-of-sight configuration to potentially cover huge areas (the accepted performance would be anywhere from 0.1-1 Mbit/s point-to-point over anywhere from 5-20km.

然後成本要夠低,希望壓在每組 US$100 的範圍:

We are aiming to bring the cost of such configuration down to $100 per unit at least.

後面的討論裡面有提到幾個社群有在建立分散式網路,一個比較知名的是德國的 Freifunk,從「Find your nearest community」這邊用節點數量排序可以看到最大的社群超過 4000 個節點,另外有兩個主流的技術處理 routing 的問題,一個是 batman-adv,另外一個是 802.11s

另外找資料的時候有發現維基百科也有頁面在介紹這個技術:「Long-range Wi-Fi」,另外這個主題也是國外一些科技 YouTuber 喜歡拍的,像是 Linus Tech Tips 之前用 UI 的設備在視線可直視的 12km 距離下跑過 100+Mbps 的速度:

這樣似乎是可以預期一般的硬體刷機加上指向性天線,是有機會達到前面提到的要求...

把 SQLite 的 VFS 掛上 WebTorrent 的 PoC Demo

Hacker News Daily 上看到「Static torrent website with peer-to-peer queries over BitTorrent on 2M records (boredcaveman.xyz)」這個討論,作者試著在網頁上跑 SQLite + VFS + WebTorrent

這好像是這陣子一連串的 combo 技累積出來的東西:

  • 首先當然是把 SQLite 丟到網頁上跑的「sql.js」,這個專案比較久了,2019 年有第一個 release;
  • 然後最近有人透過 HTTP Range (Byte serving) 實做 SQLite VFS 的「sql.js-httpvfs」,這樣就不需要一次下載整包 SQLite;

接下來就是文章作者把 HTTP Range 換掉,改用 BitTorrent 的 pieces 來處理,在網頁端的話就順勢拿 WebTorrent 來用,對於很熱門的網站來說還蠻有趣的設計,但也可以預期網頁的反應速度應該不會太快,偏 PoC...

用 PostgreSQL 的 int4range 與 GiST

發現自己根本還不熟悉 PostgreSQL 的特性,寫一下記錄起來。

產品上常常會有 coupon 與 voucher 之類的設計,這時候通常都會設定 coupon 或 voucher 的有效期間,在 MySQL 的環境下可能會這樣設計:

CREATE TABLE coupon (
  id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  code VARCHAR(255) NOT NULL,
  started_at INT UNSIGNED NOT NULL,
  ended_at INT UNSIGNED NOT NULL
);

另外是設計 index 的部份,在產品推出夠久後,通常是過期的 coupon 或 voucher 會比目前還有效的多,而還沒生效的 coupon 與 voucher 通常都不多,所以會設計成對 ended_at 放一組 B-tree index:

CREATE INDEX ON t1 (ended_at);

這個設計不算差,不過用了一些假設。

如果不想要用這些假設,可以改用 Spatial 的資料型態去模擬並且加上 index (使用到 LineString Class),這樣就直接對 a < x < b 這類查詢更有效率,不過缺點就是可讀性會比較差。

在 PostgreSQL 這邊就有更清晰的資料結構來處理這些事情,主要是有一般性的 int4rangeint8range 以及時間類的 tsrangetstzrangedaterange (參考「Range Types」這邊有更多資料型態),所以會變成:

CREATE TABLE coupon (
  id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  code VARCHAR NOT NULL,
  active_at INT4RANGE NOT NULL
);

然後用 GIST 建立 index:

CREATE INDEX ON t1 USING GIST(active_at);

後續的 query 語法就用 <@ 的語法:

SELECT COUNT(*) FROM coupon WHERE 10000 <@ active_at;

塞了 10M 筆資料後的 table 可以看到本來需要的時間是:

Time: 779.542 ms

變成:

Time: 5.510 ms

不過缺點就是 SQLite 沒支援這些資料型態,對於 test case 就一定得跑個 PostgreSQL 起來測...

DynamoDB 也有固定的 IP address 區段了

AWS 宣佈 DynamoDB 也有固定的 IP address 區段了:「AWS specifies the IP address ranges for Amazon DynamoDB endpoints」,對於使用 IP firewall 的人可以多一些控制權。

資料可以在 https://ip-ranges.amazonaws.com/ip-ranges.json 這邊抓到,裡面 serviceDYNAMODB 的就是了。

因為沒看到 IPv6 的位置,才發現 DynamoDB 目前沒有提供 IPv6 Endpoint...

AWS Transit Gateway:不用再自己處理多個 AWS 帳號之間的 routing 了

AWS 推出 Transit Gateway,讓多個 AWS 帳號之間的 routing 問題總算不用自己處理了:「New – Use an AWS Transit Gateway to Simplify Your Network Architecture」。

這個問題常出現在組織架構大一點的情境下:為了讓各單位自己付自己單位的帳,所以大家都建立了自己的 AWS 帳號。但內部還是有互相連線的需求,雖然把 IP range 都有切開,但還是得搞定彼此之間的 routing...

之前 AWS 還做了「AWS Global Transit Network」這份說明,解釋要怎麼處理 routing,在說明裡官方當時還提供了不少在雲上面建立 router 的方案。像是其中一個方式是用 Cisco 的方案做:「AWS Solution – Transit VPC」、「Overview - Transit Network VPC (Cisco CSR)」。

而現在則是可以直接用 AWS 的服務解決了:

You can attach up to 5000 VPCs to each gateway and each attachment can handle up to 50 Gbits/second of bursty traffic. You can attach your AWS VPN connections to a Transit Gateway today, with Direct Connect planned for early 2019.

每個接點都要收租用費 (美國是 $0.05/hr,一個月大約 $36;日本是 $0.07/hr,一個月大約 $50.4),另外流量要收 USD$0.02/GB,其實就是本來的 in + out 的費用 (在 EC2 同區的流量是要收 in + out 的費用的)。

AWS 允許 Hybrid Cloud 下的 DNS Query

AWS 對於 Hybrid Cloud (混合雲,通常是講與傳統機房的混搭應用,也就是雲端跟地端的混搭) 推出兩個功能,一個是讓 AWS 的 DNS Resolver 對於某些 domain 可以回機房端查詢 (雲端查詢地端 domain)。另外一種是反過來,讓機房端的 DNS Resolver 可以查 AWS 這邊的資料 (地端查詢雲端 domain):「New – Amazon Route 53 Resolver for Hybrid Clouds」。

兩者都可以自己幹,但就得花功夫自己架設,而且有很多細節得處理:

  • 建立 EC2 instance,在上面跑 Unbound,然後 EC2 instance 的 DNS servers 設定要指到這邊。
  • 由於 EC2 的 DHCP 服務沒有辦法指定發放的 IP range,所以為了多重意外而中獎 (關機的時候剛好有其他機器 DHCP 拿到這組 IP),需要開獨立的 subnet 只放固定 IP 的服務。
  • 為了系統的穩定性,需要在兩個不同 AZ (或是三個) 架設這些 DNS Resolver,所以對應有兩個或是三個 subnet 得建立。

而地端到雲端通常會簡單一些,因為地端通常都已經有內部的 DNS Resolver 可以用,通常只需要在雲上面有 proxy 的角色就可以解決。

不過現在這些 AWS 都直接提供了:

常見的區域都可以用:

Hybrid Cloud is available today in US East (N. Virginia), US East (Ohio), US West (Oregon), Europe (Ireland), Asia Pacific (Sydney), Asia Pacific (Tokyo) and Asia Pacific (Singapore), with other commercial regions to follow.

費用的部分不算便宜 (跟自己弄三台 t3.nano 比起來),但畢竟不需要自己管理,而且對於已經有機房的單位應該只是零頭而已:

Route 53 Resolver remains free for DNS queries served within your VPC. Resolver Endpoints use Elastic Network Interfaces (ENIs) costing $0.125 per hour. DNS queries that are resolved by a Conditional Forwarding Rule or a Resolver Endpoint cost $0.40 per million queries up to the first billion and $0.20 per million after that.

用 unicode-range 混合不同的字型

Combining fonts」這邊示範了如何使用 CSS 的 unicode-range 針對某些特殊字元混用不同的字型,作者利用這個技巧,把 hyphen 與 equals 換掉...:

看了一下,支援度還蠻高的?IE 支援度是 9+ 的功能...

英國計畫在 2018 年開始強制企業公佈男女的平均薪資及 Bonus

英國計畫從 2018 年開始,超過 250 人的公司必須公佈男女的平均薪資及 Bonus:「Companies will be forced to reveal their gender pay gap」:

The new rules, revealed on Friday, will apply to all companies with more than 250 employees.

除了平均薪資以及 bonus 外,還必須公開每個區間的人數:

In addition to publishing their average gender pay and bonus gap, around 8,000 employers across the country will also have to publish the number of men and women in each pay range.

目標是希望讓資訊更透明讓人力市場更健康:

The government is hoping that naming and shaming firms that pay women a lot less than men in the same jobs will push them to stop the practice, because it will make it harder for them to attract top talent.

可以看到目前估算出來的差異:

另外美國也在規劃類似的法案,不僅僅是性別,還包括了種族等其他資訊:

In the U.S., similar plans are also under discussions. President Obama announced a proposal earlier this month that would require companies with more than 100 employees to report how much they are paying their employees by race, ethnicity and gender.

AWS Public IP 的變動可以透過 Amazon SNS 訂閱

在「Subscribe to AWS Public IP Address Changes via Amazon SNS」這邊提供利用現有的 Amazon SNS 所提供的新功能。

依照說明,訂 arn:aws:sns:us-east-1:806199016981:AmazonIpSpaceChanged 就可以了:

會收到類似於這樣的東西:

{
  "create-time":"yyyy-mm-ddThh:mm:ss+00:00",
  "synctoken":"0123456789",
  "md5":"6a45316e8bc9463c9e926d5d37836d33",
  "url":"https://ip-ranges.amazonaws.com/ip-ranges.json"
}

不過之前就可以 polling 了,這個功能好像還好...

Amazon DynamoDB 筆記

Amazon DynamoDB 頁面上的介紹:

Amazon DynamoDB is a fast and flexible NoSQL database service for all applications that need consistent, single-digit millisecond latency at any scale.

資料型態的部份就跳過去了,這篇筆記的重點在於 index 的部份 (了解他如何 scale),尤其是對 RDBMS 有了解的人要如何從他所設計的架構理解 DynamoDB 的 index。

理論基礎是 Amazon 在 2007 年丟出的論文「Dynamo: Amazon’s Highly Available Key-value Store」,這篇論文影響了很多 open source project。

DynamoDB 的 index 有 Primary Key、Local Secondary Index Key (LSI) 以及 Global Index Key (GSI),在「DynamoDB Data Model」這篇有介紹。

這邊會拿 Blogger.com 這種多人的 Blog Hosting 當例子:

  • 一個 user 可以有很多 blog。(table user)
  • 一個 blog 可以有很多 post。(table blog)
  • 一篇 post 可以有很多 comment。(table post)

接下來就從 Primary Key 開始講。

Primary Key

Primary Key 保證唯一,這也是 DynamoDB 裡面可以達到 RDBMS 的 UNIQUE KEY 效果的最佳方式。

有兩種 Primary Key 的型態,一種叫做 Hash,另外一種叫做 Hash-Range。

兩種都需要指定某一個欄位是 Hash-based column,當作切割 (partition) 的依據。

第一種:Hash

以 table user 來說,可以拿 user_id 來當作 Hash-based column,裡面有 blog_id 的 list。

以 table blog 來說,可以拿 blog_id 來當作 Hash-based column,裡面有 post_id 的 list。

要注意的是,如果表格 PK 是 Hash,那麼就不能使用 LSI 與 GSI 了。只有另外一種型態 (Hash-Range) 才可以用 LSI 與 GSI。

相對的,Hash-based 的表格因為功能有限,效率通常很好 XDDD

第二種:Hash-Range

其實 Hash-Range 是一種別的 LSI,兩者最大的差異就是唯一性了。

另外一種 Primary Key 是 Hash-Range,他需要指定兩個欄位,其中其中 Hash 的欄位就如同上面的解釋,當作資料切割的依據。這邊的唯一性是指 (Hash column, Range column) 唯一,而非只有 Hash 唯一或是 Range 唯一。

剛剛說到需要指定的另外一個欄位,被稱為「Range」的原因是因為他可以有效率的以 hash + range query 查詢資料。

以 table post 來說,可以拿 blog_id 當作 Hash-based column,再拿 post_id 當作 Range-based column,等下我們介紹 LSI 時再拿發表時間欄位排序。

同理,table comment 可以拿 (post_id, commend_id) 當 PK。

Query

PK 是 Hash 的當然就是指定 Hash-based column 直接查,條件只能是等號。

PK 是 Hash-Range 的除了可以用 Hash-based column 直接查 (還是只能用等號),另外可以用 Hash-based column + Range-based column 查。

以 SQL 的想法就像是 WHERE hash_col = 123 AND range_col BETWEEN (123, 456) 的感覺。反正 Hash-based column 一定要等號。

講到這邊,其實讀過上面提到的 Amazon 那篇論文應該就大概有感覺架構是怎麼搞的了:(這是推敲出來的,未必是實際架構)

  • 用 Hash-based column 切 consistent hash ring 塞到不同機器上。PK 是 Hash 的到這邊就搞定了。
  • PK 是 Hash-Range 的,還是照上面一條提到的,用 Hash-based column 切開,所以同樣的 Hash-based column 的資料都會塞到同一台機器上,於是就可以用有效率的 ordered tree 來存放 Range-based column 的資料,這樣就可以提供 query 了。

當然,考慮到需要實做 rebalance 機制以逐步擴充,這邊 consistent hash ring 的部份的作法可以更細膩,不過就不是這篇要談的重點了。

接下來要講重頭戲 LSI 與 GSI 了。

Local Secondary Index (LSI) 與 Global Secondary Index (GSI)

前面有提到 LSI 與 GSI 必須 PK 是 Hash-Range 的情況下能用,兩者都不強制唯一性。

LSI 與 GSI 都是 (Hash-column based, Range-column based) 的形式,差別在 LSI 的 Hash-column based column 必須跟 PK 的相同,GSI 的可以不用一樣。

所以對於 table post 可以加一個 LSI (blog_id, post_datetime),就可以用 WHERE blog_id = 123 ORDER BY post_datetime DESC 拉出對應的文章了。

同理,table comment 是 (post_id, comment_datetime)。