Author: Ken

  • 在AWS EC2 instance 上添加一個swap

    雖然這是一個常規動作,但是我最近發現一個特別的配置。

    OOM 不是經常發生的事情,他是一個偶發事件,通常是因為業務流量突增,或是Java memory leak,之所以要說Java 因為他最容易出問題,code 寫得好就是Enterprise level,code 寫得差就是 OOM level。

    一般來說我會將swap 空間放置於ebs 上,這樣做沒什麼問題,但極端情況下很可能會導致整個ec2 失去響應,那麼這時候你可以使用第二塊較小的單獨的data volume 來做swap,或者直接啟動具有instance store 的ec2,使用instance store 的高速ssd 來swap。

    使用ebs 來swap:

    fallocate -l 1G /home/swapfile
    chmod 600 /home/swapfile
    mkswap /home/swapfile
    swapon /home/swapfile
    
    Setting up swapspace version 1, size = 1024 MiB (1073737728 bytes)
    no label, UUID=12438694-fc0d-4e8b-b7a8-41c6a9e38971

    添加到fstab:

    /home/swapfile  none    swap    sw      0       0

    使用instance store 來swap

    mkswap /dev/nvme1n1
    swapon /dev/nvme1n1
    
    Setting up swapspace version 1, size = 54.9 GiB (58999992320 bytes)
    no label, UUID=3afa04d4-787f-4c31-a491-3581a41c3bb1

    添加到fstab:

    UUID=3afa04d4-787f-4c31-a491-3581a41c3bb1  none    swap    sw      0       0

    instance store 做swap 的效果非常好,因為本地的高速ssd 可以承載較高的iops 和throughput ,可以抗住數倍於memory size 的workload,當然,這還要看你的應用類型和可以接受的響應時間。

    OK,這些方式都要花錢,那麼有沒有不花錢,又可以避免在短暫的異常下OOM 的辦法?畢竟一說到要花更多的錢,老闆都會很不開心。

    今天要說的是zram,從名字就可以看出他就是zip ram的意思,在Amazon Linux 2023 中已經預裝了相關的組件,可以直接修改配置文件即可啟用這項功能。

    我也是偶然發現他的,因為我發現在micro type 的instance 上才會有swap 而更大的instance type 沒有,而且在更換instance type 的時候他會自己更動。

    在預設的配置文件中,只有memory 小於800M 的instance type 才會啟用一個和memory 大小相同的zram device,只需要將host-memory-limit 改為超過當前instance type memory size 的大小,重啟即可。

    
    cat /usr/lib/systemd/zram-generator.conf 
    # This config file enables a /dev/zram0 device with the default settings:
    # — size — same as available RAM or 8GB, whichever is less
    # - host-memory-limit: Enable only on small instance types (less than 800MB)
    # — compression — most likely lzo-rle
    #
    # To disable, uninstall zram-generator-defaults or create empty
    # /etc/systemd/zram-generator.conf file.
    
    # zram0 defaults to swap
    [zram0]
    # Up to 8GiB of zram, follows Fedora/CentOS defaults
    zram-size = min(ram, 8192)
    # Instances with more than 800MiB of RAM don't need this on AL2023
    host-memory-limit=4096
    # This is the kernel default, fastest but maybe we want zstd for
    # small instances which compresses more ?
    compression-algorithm=lzo-rle
    

    看看加上沒有:

    zramctl 
    NAME       ALGORITHM DISKSIZE  DATA  COMPR TOTAL STREAMS MOUNTPOINT
    /dev/zram0 lzo-rle       3.7G 11.7M 336.5K  708K       1 [SWAP]

    壓縮比例可以到多少?

    這是個玄學,我還沒有找到可信的評測,但是廣泛的評價是可以從 1:1 到 3:1,畢竟放入memory 的data 有些是已經壓縮過的,那麼就只能是團進團出,沒壓縮過的data 也許可以多一點點。

    回到之前的問題,這主要是為了解決在短暫的異常下不要那麼容易OOM,他也可能帶來一些副作用,比如CPU負載上升,但和不要OOM 比起來似乎沒有那麼重要,持續的memory leak 仍會導致OOM發生,任何形式的swap 都只是應對偶然的突發狀況,而不是長期性的超過memory size 的使用,如果已經預期當前的application workload 會使用到超過instance type 的memory size,就應該要及時的升級。

  • 斷斷續續看完了《生死場》

    我想蕭紅的獨特應該是在於,他沒有那麼左。

    花了大概20天的時間,斷斷續續看完了《生死場》,因為語言帶有那個年代的特徵,台灣的版本不像中國的版本竄改了許多當時的語言,使得我讀起來頗費一些心思去想到底是什麼意思,還有一些口語又沒那麼口語化,使得我揣測東北人講那句話的口氣,但就還好,因為罵人的言語也不過那麼幾句。

    魯迅作序並不是什麼好事,畢竟他弟弟在文學方面的成就比他高得多,充其量算是個現在的公知,就像很多人說的,還好他死在了舊社會。

    《生死場》中對於底層民眾的描繪有獨特的地方,因為有一些場景竟然是我想像不到的,例如月英的綠色牙齒,其他的描繪,或多或少算是見過一些。我並不認為最後幾個章節對於滿洲國的描繪是他人生中的體驗,因為看起來沒有深度,更像是為了迎合當時的抗日潮流而寫就的一些文字,我並不是說日軍沒有作惡,而是那些道聽途說的作惡多端和前面對於生死的描繪,比起來顯得事不關己。

    而其中關於地主階級對農民殘酷壓榨的描繪,更顯得突兀,如果基於小說本身的衝突效果,當然沒問題,但這和《呼蘭河傳》中關於地主爺爺對待租戶的的描繪完全兩極,而《呼蘭河傳》是他在人生歲月的最後完成,我當然願意相信後面的作品更接近他短暫人生中的真實。

    比起來陸老師強力推薦的《邊城》聽起來更像靡靡之音啊……

  • 將WordPress 的Redis plugin 配置為使用AWS ElastiCache redis cluster

    這個plugin 已經存在很多年,一直以來我都使用single node 的方式,因為wordpress 的cache data 從mysql 取一遍沒有太大的難度,但是對於高負載的網站來說,這總是不合理的。

    而single node 有他壞掉後就要從database reload data 的問題,雖然眾多的雲端服務商提供了failover 的機制來避免node 壞掉不可用的問題,但難免會有某些網站需要大量的寫入,比如wordpress.com這樣的。

    這個plugin 應該很早就支持cluster 的方式了,只不過我從來沒注意過,而他的github 又語焉不詳,我想他可能是想要賣他的pro 版本。

    嘗試了一下,有一點需要注意的地方:

    single node 方式支持tls,但cluster mode 不支持tls,所以elasticache serverless 不行,因為serverless 的tls 無法關閉,只能是self design cluster mode enabled。

    我認為作者在這個地方隱晦的表明了這一點,雖然他沒有直接講出來。

    用如下的方式配置wp-config.php 即可。

    /**wp redis object cache*/
    define('WP_REDIS_CLIENT','pecl');
    define('WP_REDIS_CLUSTER', [ 'tcp://valkey-cluster.clustercfg.apn3.cache.amazonaws.com:6379',] );

    那麼php session 呢?

    修改php.ini 原來的配置,如下兩處,

    ;session.save_handler = redis
    session.save_handler = rediscluster
    
    ;session.save_path = "tcp://valkey.0001.apne1.cache.amazonaws.com"
    session.save_path = "seed[]=valkey-cluster.clustercfg.apn3.cache.amazonaws.com:6379"

    一個有用的測試session 的script

    <?php
    //simple counter to test sessions. should increment on each page reload.
    session_start();
    $count = isset($_SESSION['count']) ? $_SESSION['count'] : 1;
    echo $count;
    
    $_SESSION['count'] = ++$count;

    再看看ElastiCache 裡面有了沒,雖然不應該用keys command ……

    valkey-cluster.clustercfg.apn3.cache.amazonaws.com:6379> keys *PHP*
    1) "PHPREDIS_CLUSTER_SESSION:d9uv2emobrcmpc7g5fk7bduqgq"
    2) "PHPREDIS_CLUSTER_SESSION:d30c1t3kln5df0uij8f7gqibnt"
    3) "PHPREDIS_CLUSTER_SESSION:bh5buktvsumi1k6j7hcpjcil6c"
    4) "PHPREDIS_CLUSTER_SESSION:3s6jagi622rt0nqdof9i1otd09"
    5) "PHPREDIS_CLUSTER_SESSION:fq6tnls1dcfv0bspljq9j2k5i4"
    6) "PHPREDIS_CLUSTER_SESSION:1p1ajkvr641cp99edm9cm74o6s"

    2025-08-22 update

    糾正我的錯誤,這個plugin 是支持ElastiCache serverless 的,wp-config.php 中可以按照如下配置:

    /**wp redis object cache*/
    define('WP_REDIS_CLIENT', 'pecl');
    define('WP_REDIS_HOST', 'valkey.serverless.apn3.cache.amazonaws.com');
    define('WP_REDIS_PORT', 6379);
    define('WP_REDIS_SCHEME', 'tls');
    define('WP_REDIS_DATABASE', 0);

    2025-11-16 update

    我不是很確定可以使用ElastiCache serverless 是因為我的配置下他還沒有進行scaling,只有一個master 和一個slave,效果等同於主從複製模式,如果存在多個shards,是否還可用,能否正常跳轉?

    valkey-serverless:6379> CLUSTER INFO
    cluster_state:ok
    cluster_slots_assigned:16384
    cluster_slots_ok:16384
    cluster_slots_pfail:0
    cluster_slots_fail:0
    cluster_known_nodes:2
    cluster_size:1
    cluster_current_epoch:0
    cluster_my_epoch:0
    cluster_stats_messages_sent:0
    cluster_stats_messages_received:0
    total_cluster_links_buffer_limit_exceeded:0

    okay,我創建了一個多分片的集群,實驗證明,這個plugin 看起來無法處理MOVED,之所以可暫時使用ElastiCache serverless 是因為他只有一個shard:

    wp redis status
    RedisException: MOVED 12096 valkey-cluster.cache.amazonaws.com:6379 in /home/www/bbken.org/wp-content/object-cache.php:1934
    Stack trace:
    #0 /home/www/bbken.org/wp-content/object-cache.php(1934): Redis->get()
    #1 /home/www/bbken.org/wp-content/object-cache.php(193): WP_Object_Cache->get()
    #2 /home/www/bbken.org/wp-includes/functions.php(1779): wp_cache_get()
    #3 /home/www/bbken.org/wp-includes/load.php(939): is_blog_installed()
    #4 /home/www/bbken.org/wp-settings.php(176): wp_not_installed()
    #5 phar:///usr/local/bin/wp/vendor/wp-cli/wp-cli/php/WP_CLI/Runner.php(1374): require('...')
    #6 phar:///usr/local/bin/wp/vendor/wp-cli/wp-cli/php/WP_CLI/Runner.php(1293): WP_CLI\Runner->load_wordpress()
    #7 phar:///usr/local/bin/wp/vendor/wp-cli/wp-cli/php/WP_CLI/Bootstrap/LaunchRunner.php(28): WP_CLI\Runner->start()
    #8 phar:///usr/local/bin/wp/vendor/wp-cli/wp-cli/php/bootstrap.php(84): WP_CLI\Bootstrap\LaunchRunner->process()
    #9 phar:///usr/local/bin/wp/vendor/wp-cli/wp-cli/php/wp-cli.php(35): WP_CLI\bootstrap()
    #10 phar:///usr/local/bin/wp/php/boot-phar.php(20): include('...')
    #11 /usr/local/bin/wp(4): include('...')
    #12 {main}
    Error: Error establishing a Redis connection. To disable Redis, delete the `object-cache.php` file in the `/wp-content/` directory.

    2025-11-17 update

    但是經過AI 對於source code 的分析,以及我的反覆測試,如下的配置實際測試可以使用:

    /**wp redis object cache*/
    define('WP_REDIS_CLIENT', 'phpredis');
    define('WP_REDIS_CLUSTER', [
        'tls://clustercfg.valkey-cluster.cache.amazonaws.com:6379',
    ]);
    define('WP_REDIS_SSL_CONTEXT', [
        'verify_peer' => false,
    ]);
    

    從CloudWatch 的指標看起來,三個節點中都有讀寫keys,沒有問題,完美。