Hi, I am Steven Huang (@steventtud).
A backend developer working for Splashtop.
Splashtop 是一家遠端桌面公司。
(remote desktop access solution)
OK! 接下來回到今天的主題!
migration 中針對已經建立的的 table 做修改的動作,就會使用到 Mysql 的 alter table 指令。
a migration
change_table(:users) do |t|
t.string :company_name
t.change :birthdate, :datetime
end
輸入 rake db:migrate
後會產生這樣的 sql 指令
ALTER TABLE `users` ADD `im_handle` varchar(255)
ALTER TABLE `users` ADD `company_id` int(11)
ALTER TABLE `users` CHANGE `updated_at` `updated_at` datetime DEFAULT NULL
從以上可以了解
alter table 就是修改已存在的 table
資料量小的時候 alter table 很簡單
但如果 Table 資料量達千萬級(rows > 10 millions)
而且有讀寫分離的情況下(has read replicas)
Alter Table 可能成為你的惡夢。
(altering table would be your nightmare)
這次的 Talk 將會分享如何克服讀寫分離的 slave lag,成功的alter table 大型資料庫。
通常我們不會透漏公司資料量的規模
但是我剛剛在逛官網的時候…
這樣大致了解目前敝公司處理的資料量
Solution:
lhm - Online MySQL schema migrations
一般的 migration 會使用 alter table
來修改資料庫
在 alter table 時,原本的 Table 是無法寫入的。
新 Table 修改完畢後,將原本的 Table 與新 Table 交換名稱,並將原始的 Table 刪除。
Lhm is a solution for this situation.
Lhm 的作法是使用 MySQL Trigger,當原始 Table 寫入的時候,mysql trigger 會同步到新的 Database。
等到結束的時候兩個 Table 互換,write lock 持續的時間很短。
Example of lhm migration
require 'lhm'
class MigrateUsers < ActiveRecord::Migration
def self.up
Lhm.change_table :users do |m|
m.add_column :arbitrary, "INT(12)"
m.add_index [:arbitrary_id, :created_at]
m.ddl("alter table %s add column flag tinyint(1)" % m.name)
end
end
def self.down
Lhm.change_table :users do |m|
m.remove_index [:arbitrary_id, :created_at]
m.remove_column :arbitrary
end
end
end
What is read replica?
在大型系統中,為了讓主要的 Database 記憶體和CPU的使用量更穩定,通常會使用讀寫分離來分擔壓力
如果你在讀寫分離的 Database 中使用 lhm,並且沒有實際去了解 lhm 的機制。很可能遇到的問題是:
lhm 在新版中推出了一個 SlaveLag Throttler
SlaveLag Throttler 大致上的概念是:
這邊可以看 Lhm::Throttler::SlaveLag 的原始碼
其中最關鍵的一段
def execute
sleep(throttle_seconds)
end
def throttle_seconds
lag = max\_current\_slave_lag
if lag > @allowed_lag && @timeout_seconds < MAX_TIMEOUT
Lhm.logger.info("Increasing timeout between strides from #{@timeout_seconds} to #{@timeout_seconds * 2} because #{lag} seconds of slave lag detected is greater than the maximum of #{@allowed_lag} seconds allowed.")
@timeout_seconds = @timeout_seconds * 2
elsif lag <= @allowed_lag && @timeout_seconds > INITIAL_TIMEOUT
Lhm.logger.info("Decreasing timeout between strides from #{@timeout_seconds} to #{@timeout_seconds / 2} because #{lag} seconds of slave lag detected is less than or equal to the #{@allowed_lag} seconds allowed.")
@timeout_seconds = @timeout_seconds / 2
else
@timeout_seconds
end
end
步驟拆解
初始化:
# INITIAL_TIMEOUT 是最小的等待時間,同時也是執行初始的等待時間。
INITIAL_TIMEOUT = 0.1
# MAX_TIMEOUT 是最長的等待時間,後面我用100秒來簡化之。
MAX_TIMEOUT = 0.1 * INITIAL_TIMEOUT
# allow_lag 是我們允許 slave 的延遲時間。
# 這是我們唯一可以自行設定的值。
allow_lag = 10
# 初始的等待時間
timeout_seconds = INITIAL_TIMEOUT
每次執行的時候會偵測最大的 slave lag
# 現在最大的 slave lag
lag = max_current_slave_lag
第一次
如果 lag > allow_lag 且 @timeout_seconds < MAX_TIMEOUT(100秒)
@timeout_seconds = 0.1 * 2 = 0.2
睡 0.2 秒
第二次
如果 lag > allow_lag 且 @timeout_seconds < MAX_TIMEOUT(100秒)
@timeout_seconds = 0.2 * 2 = 0.4
睡 0.4 秒
第三次
如果 lag > allow_lag 且 @timeout_seconds < MAX_TIMEOUT(100秒)
@timeout_seconds = 0.4 * 2 = 0.8
睡 0.8 秒
第4次
如果 lag > allow_lag 且 @timeout_seconds < MAX_TIMEOUT(100秒)
@timeout_seconds = 0.8 * 2 = 1.6
睡 1.6 秒
第5次
如果 lag <= allow_lag 且 @timeout_seconds > INITIAL_TIMEOUT(0,1)
@timeout_seconds = 0.8 / 2 = 0.8
睡 0.8
95%以上都會如前面兩個方式執行,例外為:
most pictures in this slide are from a article Rails Migrations at Scale
Thanks for listening.
or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Do you want to remove this version name and description?
Syncing