讓 Python 輸出變豐富的 Rich

Hacker News 上看到的 Python 專案,讓 terminal 輸出變得更好看:「Rich is a Python library for rich text and beautiful formatting in the terminal.」。

看到當下吸引我的地方在於表格:

from rich.console import Console
from rich.table import Column, Table

console = Console()

table = Table(show_header=True, header_style="bold magenta")
table.add_column("Date", style="dim", width=12)
table.add_column("Title")
table.add_column("Production Budget", justify="right")
table.add_column("Box Office", justify="right")
table.add_row(
    "Dev 20, 2019", "Star Wars: The Rise of Skywalker", "$275,000,000", "$375,126,118"
)
table.add_row(
    "May 25, 2018",
    "[red]Solo[/red]: A Star Wars Story",
    "$275,000,000",
    "$393,151,347",
)
table.add_row(
    "Dec 15, 2017",
    "Star Wars Ep. VIII: The Last Jedi",
    "$262,000,000",
    "[bold]$1,332,539,889[/bold]",
)

console.print(table)

輸出長這樣:

另外還有不少功能也不錯,會讓畫面豐富不少。

Vim 的 virtualedit 與 GNU Make 內的 .PHONY

在「Writing a Book with Pandoc, Make, and Vim」這邊看到作者在講他怎麼用 Pandoc + GNU Make + Vim 寫書,不過我這邊看到兩個有趣的東西 (標題提到的那兩個),拉出來寫一下...

一個是 Vim 的 set virtualedit=all,可以不受限制的移動,等到實際編輯時再產生出對應需要的空白,這對於畫表格會方便不少:

另外一個是 GNU Make 的用法,平常我們都是在 .PHONY 裡指定實際上不會存在的 target:

.PHONY: clean
clean:
        rm -rf ./output

這邊作者提供的方式是產生一個叫做 phony 的 target,然後就不需要在 .PHONY 裡條列,而是各自在自己的 target 裡面引用 phony

.PHONY: phony
clean: phony
        rm -rf ./output

不過作者有提到效能問題:

Note that this trick can slow down huge Makefiles.

另外作者又提醒我 draw.io 這個好用的工具,之前用過幾次後就忘記了...

Amazon Redshift 會自動在背景重新排序資料以增加效能

Amazon Redshift 的新功能,會自動在背景重新排序資料以增加效能:「Amazon Redshift introduces Automatic Table Sort, an automated alternative to Vacuum Sort」。

版本要到更新到 1.0.11118,然後預設就會打開:

This feature is available in Redshift 1.0.11118 and later.

Automatic table sort is now enabled by default on Redshift tables where a sort key is specified.

重新排序的運算會在背景處理,另外帶一些行為學習分析:

Redshift runs the sorting in the background and re-organizes the data in tables to maintain sort order and provide optimal performance. This operation does not interrupt query processing and reduces the compute resources required by operating only on frequently accessed blocks of data. It prioritizes which blocks of table to sort by analyzing query patterns using machine learning.

算是丟著讓他跑就好的東西,升級上去後可以看一下 CloudWatch 的報告,這邊沒有特別講應該是還好... XD

在 SQL 裡面避免大量刪除資料的方式

看到 Percona 的「An Overview of Sharding in PostgreSQL and How it Relates to MongoDB’s」這篇,雖然是在講 PostgreSQL 上的 sharding (以及 partition),突然想到好像沒寫過要怎麼避免大量刪除資料的操作...

一個常見的情境是,想要讓某個表格只保留這一個月的資料,所以每個月開頭都會跑一隻 cron job 負責刪掉上個月的資料,像是 DELETE FROM xxx WHERE timestamp < yyy; 這樣的指令。

這個方式無論是在 PostgreSQL 或是 MySQL 都需要很多時間與 I/O 資源,而透過 partition 將不同時間區段切開到不同的表格,再用 TRUNCATE 直接清空表格剛好可以解這樣的問題。

Percona 的文章裡說了一些 PostgreSQL 的歷史與目前的進展。

在 PostgreSQL 9 或更早以前的版本,一個常見的作法是透過 table inheritance 實做 partition,然後用再用 function 實做 INSERT

CREATE TABLE temperature (
  id BIGSERIAL PRIMARY KEY NOT NULL,
  city_id INT NOT NULL,
  timestamp TIMESTAMP NOT NULL,
  temp DECIMAL(5,2) NOT NULL
);

CREATE TABLE temperature_201901 (CHECK (timestamp >= DATE '2019-01-01' AND timestamp <= DATE '2019-01-31')) INHERITS (temperature);
CREATE TABLE temperature_201902 (CHECK (timestamp >= DATE '2019-02-01' AND timestamp <= DATE '2019-02-28')) INHERITS (temperature);
CREATE TABLE temperature_201903 (CHECK (timestamp >= DATE '2019-03-01' AND timestamp <= DATE '2019-03-31')) INHERITS (temperature);

CREATE OR REPLACE FUNCTION temperature_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
    IF ( NEW.timestamp >= DATE '2019-01-01' AND NEW.timestamp <= DATE '2019-01-31' ) THEN INSERT INTO temperature_201901 VALUES (NEW.*);
    ELSIF ( NEW.timestamp >= DATE '2019-02-01' AND NEW.timestamp <= DATE '2019-02-28' ) THEN INSERT INTO temperature_201902 VALUES (NEW.*);
    ELSIF ( NEW.timestamp >= DATE '2019-03-01' AND NEW.timestamp <= DATE '2019-03-31' ) THEN INSERT INTO temperature_201903 VALUES (NEW.*);
    ELSE RAISE EXCEPTION 'Date out of range!';
    END IF;
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;

在 PostgreSQL 10 之後,就直接支援一些與 partition 相關的設計,像是這樣:

CREATE TABLE temperature (
  id BIGSERIAL NOT NULL,
  city_id INT NOT NULL,
  timestamp TIMESTAMP NOT NULL,
  temp DECIMAL(5,2) NOT NULL
) PARTITION BY RANGE (timestamp);

CREATE TABLE temperature_201901 PARTITION OF temperature FOR VALUES FROM ('2019-01-01') TO ('2019-02-01');
CREATE TABLE temperature_201902 PARTITION OF temperature FOR VALUES FROM ('2019-02-01') TO ('2019-03-01');
CREATE TABLE temperature_201903 PARTITION OF temperature FOR VALUES FROM ('2019-03-01') TO ('2019-04-01');

雖然還是有些限制,但可以看出比起以前簡單不少。

而有了 partition 後,文章的後續就在討論這跟 MongoDB 的 sharding 有什麼關係,但這就不是我關注的事情了...

Google 內部的系統 (以及外部可能的 Open Source 替代方案)

Hacker News Daily 上看到的 jhuangtw-dev/xg2xg,整理了 Google 內部服務以及可能的替代方案。

主要是提供給離開 Google 的工程師,替代方案中包括了 Google 自己公佈的,已經其他的 open source 替代方案:

by ex-googlers, for ex-googlers - a lookup table of similar tech & services

A handy lookup table of similar technology and services to help ex-googlers survive the real world :) pull-requests very welcomed. Please do not list any confidential projects!

專案的發起人看起來是個台灣人...

在 Galera Cluster 上的 DDL 操作 (e.g. ALTER TABLE)

Percona 整理了一份關於 Galara Cluster 上 DDL 操作的一些技巧,這包括了 Percona XtraDB ClusterMariaDB 的版本:「How to Perform Compatible Schema Changes in Percona XtraDB Cluster (Advanced Alternative)?」。

在不知道這些技巧前,一般都是拿 Percona Toolkit 裡的 pt-online-schema-change 來降低影響 (可以降的非常低),所以這些技巧算是額外知識,另外在某些極端無法使用 pt-online-schema-change 的情境下也可以拿來用...

裡面的重點就是 wsrep_OSU_method 這個參數,預設的值 TOI 就是一般性的常識,所有的指令都會被傳到每一台資料庫上執行,而 RSU 則是會故意不讓 DDL 操作 (像是 ALTER TABLE) 被 replicate 到其他機器,需要由管理者自己到每台機器上執行。

利用這個設定,加上透過工具將流量導到不同後端的資料庫上,就有機會分批進行修改,而不需要透過 pt-online-schema-change 這種工具。

Amazon DynamoDB 的 Global Tables 推到東京了...

DynamoDBGlobal Tables 可以把 DynamoDB 複製到其他區域,讓各地存取自己的資料:

剛剛看到 AWS 宣佈這個功能展到 ap-northeast-1 (東京) 了:「Amazon DynamoDB Global Tables Now Available in Three Additional Asia Pacific Regions」。

Global tables is now available in the Asia Pacific (Tokyo), Asia Pacific (Seoul), and Asia Pacific (Sydney) Regions.

這樣測起來就更接近實際的情況了...

Percona XtraDB Cluster 裡各種與 LOCK 相關的指令會產生的效果

在「FLUSH and LOCK Handling in Percona XtraDB Cluster」這邊看到在 Percona XtraDB Cluster 內各種不同形式的 LOCK 指令會有不同的效果。有些跟一開始用的印象已經不太一樣了...

FLUSH TABLE WITH READ LOCKFLUSH TABLE <tablename> (WITH READ LOCK|FOR EXPORT) 都會直接讓整個 node 卡住,但 LOCK TABLE <tablename> READ/WRITE 就只會卡對應的表格,另外 GET_LOCK 本來應該是完全不支援,現在似乎變成 experimental 的功能了 (參考「PXC Strict Mode」這邊),這樣一來 MogileFS 的資料庫部分就可以在上面跑了嗎?(當初就是因為這個問題而另外弄一組 DRBD + HeartbeatMySQL 起來跑 XD)

之後看一下什麼時候加進去的...

一路從 MySQL 5.5 升級到 MySQL 8.0 的故事...

在「Migrating to MySQL 8.0 without breaking old application」這邊看到這個有趣的故事 XD 這是作者的應用程式 DrupalMySQL 5.5 一路升級到 8.0 的過程記錄...

真正的問題發生在 5.7 到 8.0:

原因是 Drupal 用到關鍵字了:

In fact, this old Drupal, uses a table name that is now part of the reserved keywords. It’s always advised to verify what are the new keywords reserved for MySQL itself. New features can also mean new keywords sometimes.

修正後就好了:

話說依照「File:Drupal release timeline.png」這邊的資訊,Drupal 6.2 也十年左右了?應該是 PDO 剛開始要推廣的年代,不知道他跑哪個版本的 PHP...

另外 MySQL 的升級意外的順利?雖然是一步一步升,但沒遇到什麼大問題...

Fortnite 看起來沒上 Auto Scaling?(或是沒正確設好?)

Fortnite 遊戲的伺服器放在 AWS 上,看起來這波 Meltdown 的安全更新 (KPTI) 造成非常大的 overhead:

不過看起來出了問題:

We wanted to provide a bit more context for the most recent login issues and service instability. All of our cloud services are affected by updates required to mitigate the Meltdown vulnerability. We heavily rely on cloud services to run our back-end and we may experience further service issues due to ongoing updates.

最有可能的是把 AWS 當作一般的 VPS 在用,另外一種可能是有部份內部服務沒有 scale,造成上了 KPTI 後 overhead 增加,就卡住了...