分类 工作&技术 下的文章

刚在ns看到这图。
闹了半天,阿里也只不过是vps?云?那是浮云?
一个真的云,在出现宕机时,应该能够自动迁移,无缝要求可能太高,但秒级应该行吧? 2-5分钟,我宁肯相信是工作人员在更换物理机。

OarQ0DUBIbGom0dffsX9OI.png

经过我多年潜心研究揭露出一个真相:仅仅一只1C1G小鸡就能满足我的所有要求了。扎心。。。
蚊子肉也是肉,1C1G也是鸡,基于此,我特地找了手里三只1C1G的小鸡来对比下。

  • 有钱就是爷,即使只1o,也比免费好。但NetCup低价机超售也确实太狠了,300多分的GB5,但谁也没想把1o的机器的CPU往死里跑吧。4K一般,不重度使用应该没问题。 (我用超售而不是限制的字眼,是因为IO和CPU跑分波动很大,而限制的话分应该很稳定)
  • 甲骨文在三者居中。CPU免费的能有1o的水平让我很意外。4K凑合,一般的应用应该不卡。甲骨文主要问题就在于是玄学封号,不过,我始终认为,没有玄学,只有滥用。就算是冤枉的,也只是因为用户行为与滥用近似被误伤。
  • GCP只能供着。4K IO属于打个 ls 都要卡一下的级别,然后在CPU高占用下可能是积分制会迅速限制性能。当然,还有祖传的潜在反撸的可能。但gcp的好处是,如果不滥用不欠费,很稳,跑跑小业务,比如低频后端api还是可以的。

网络就不扯了,三家的网络国际都很好,对中国当然都一塌糊涂。这个谁都知道。

NetCup 1o

ISP        : netcup GmbH
ASN        : AS197540 netcup GmbH
Host       : NETCUP-GMBH
Location   : Nuremberg, Bavaria (BY)
Country    : Germany

fio Disk Speed Tests (Mixed R/W 50/50) (Partition /dev/vda3):
---------------------------------
Block Size | 4k            (IOPS) | 64k           (IOPS)
  ------   | ---            ----  | ----           ---- 
Read       | 37.45 MB/s    (9.3k) | 527.12 MB/s   (8.2k)
Write      | 37.54 MB/s    (9.3k) | 529.90 MB/s   (8.2k)
Total      | 75.00 MB/s   (18.7k) | 1.05 GB/s    (16.5k)
           |                      |                     
Block Size | 512k          (IOPS) | 1m            (IOPS)
  ------   | ---            ----  | ----           ---- 
Read       | 725.19 MB/s   (1.4k) | 788.18 MB/s    (769)
Write      | 763.72 MB/s   (1.4k) | 840.67 MB/s    (820)
Total      | 1.48 GB/s     (2.9k) | 1.62 GB/s     (1.5k)

Geekbench 5 Benchmark Test:
---------------------------------
Test            | Value                         
                |                               
Single Core     | 377                           
Multi Core      | 365   

Oracle 免费AMD

ISP        : Oracle Corporation
ASN        : AS31898 Oracle Corporation
Host       : Oracle Cloud Infrastructure (ap-tokyo-1)
Location   : Tokyo, Tokyo (13)
Country    : Japan

fio Disk Speed Tests (Mixed R/W 50/50) (Partition /dev/sda2):
---------------------------------
Block Size | 4k            (IOPS) | 64k           (IOPS)
  ------   | ---            ----  | ----           ---- 
Read       | 6.37 MB/s     (1.5k) | 26.46 MB/s     (413)
Write      | 6.37 MB/s     (1.5k) | 26.97 MB/s     (421)
Total      | 12.74 MB/s    (3.1k) | 53.44 MB/s     (834)
           |                      |                     
Block Size | 512k          (IOPS) | 1m            (IOPS)
  ------   | ---            ----  | ----           ---- 
Read       | 24.50 MB/s      (47) | 24.17 MB/s      (23)
Write      | 26.01 MB/s      (50) | 26.68 MB/s      (26)
Total      | 50.51 MB/s      (97) | 50.85 MB/s      (49)

Geekbench 5 Benchmark Test:
---------------------------------
Test            | Value                         
                |                               
Single Core     | 336                           
Multi Core      | 310 

Google Cloud 免费E2-Micro

ISP        : Google LLC
ASN        : AS15169 Google LLC
Host       : Google Cloud (us-west1)
Location   : The Dalles, Oregon (OR)
Country    : United States

fio Disk Speed Tests (Mixed R/W 50/50) (Partition /dev/sda1):
---------------------------------
Block Size | 4k            (IOPS) | 64k           (IOPS)
  ------   | ---            ----  | ----           ---- 
Read       | 406.00 KB/s    (101) | 5.79 MB/s       (90)
Write      | 428.00 KB/s    (107) | 6.09 MB/s       (95)
Total      | 834.00 KB/s    (208) | 11.89 MB/s     (185)
           |                      |                     
Block Size | 512k          (IOPS) | 1m            (IOPS)
  ------   | ---            ----  | ----           ---- 
Read       | 27.53 MB/s      (53) | 37.68 MB/s      (36)
Write      | 29.45 MB/s      (57) | 40.94 MB/s      (39)
Total      | 56.98 MB/s     (110) | 78.62 MB/s      (75)

Geekbench 5 Benchmark Test:
---------------------------------
Test            | Value                         
                |                               
Single Core     | 475                           
Multi Core      | 99  

昨天发了go版的,不过会搭建go开发环境进行编译的人毕竟不多,发编译后的二进制码也不是我作风。今天发一个bash脚本版的吧。
感谢cctv,感谢gpt,这代码是直接让它改写的go,我没有改动。测试了一下没问题。
我说说使用步骤:

  1. 把代码保存到服务器上这个不用说了吧,比如名字叫ovh.sh,然后 chmod +x ovh.sh了。当然,不加x也可以,那就运行的时候bash ovh.sh。
  2. 在telegram中,加 @botfather ,建立一个自己的机器人,好了后,注意保存 token 。怎么建自己网上查吧。当然,如果你有机器的人话,直接用它就可以了。
  3. 在tg中,加 @userinfobot , 获得自己的 id。
  4. 自己加自己的bot,一定要 /start ,简单说,自己和自己bot说句话。这样bot才有权限发消息给自己。
  5. 安装jq,如果你没有的话。 sudo apt install jq
  6. 安装screen,如果你没有的话, sudo apt install screen
  7. 运行 screen,进去后, ./ovh.sh 你的token 你的id
  8. ctrl-ad退出screen。 然后等待吧。

为了验证上面的tg参数是否正确,可以在第6步后, ./ovh.sh 你的token 你的id test 试运行一下,它会报告法国有货,即发送通知到Tg: Server availability changed to: 72H in datacenter: bhs。没问题的话就ctrl-c,然后继续第7步。

#!/bin/bash

if [ "$#" -lt 2 ]; then
    echo "Usage: $0 <telegram_bot_token> <chat_id> [test]"
    exit 1
fi

TELEGRAM_BOT_TOKEN=$1
CHAT_ID=$2
TEST_MODE=$3
API_URL="https://ca.ovh.com/engine/apiv6/dedicated/server/datacenter/availabilities/?excludeDatacenters=false&planCode=24ska01&server=24ska01"

send_telegram_notification() {
    local datacenter=$1
    local availability=$2
    local message="Server availability changed to: $availability in datacenter: $datacenter"
    
    echo "Sending notification: $message"

    curl -s -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendMessage" \
        -d "chat_id=$CHAT_ID" \
        -d "text=$message" >/dev/null

    echo "Notification sent."
}

check_availability() {
    echo "Fetching server availability data..."

    response=$(curl -s "$API_URL")

    if [ -z "$response" ]; then
        echo "Failed to fetch data."
        return
    fi

    echo "Received JSON response: $response"

    if [ "$TEST_MODE" == "test" ]; then
        echo "Test mode enabled. Forcing bhs datacenter availability to 72H."
        response=$(echo "$response" | jq '.[0].datacenters |= map(if .datacenter == "bhs" then .availability = "72H" else . end)')
    fi

    echo "$response" | jq -c '.[0].datacenters[]' | while read -r datacenter; do
        availability=$(echo "$datacenter" | jq -r '.availability')
        name=$(echo "$datacenter" | jq -r '.datacenter')

        echo "Checking datacenter: $name, availability: $availability"

        if [ "$availability" != "unavailable" ]; then
            echo "Availability change detected: $availability in datacenter: $name"
            send_telegram_notification "$name" "$availability"
            break
        fi
    done

    echo "Finished checking all datacenters."
}

while true; do
    check_availability
    sleep 60
done

前几天正在写博客评点哪吒,结果OVH放货了KS-A,等写完发现,已经卖完了。这不得不拍断大腿了。
赶紧补救,写个监控KS-A放货的玩意,下次一定要把握住了。
程序就是每一分钟去ovh网页上拉一下库存,如果有,就telegram赶紧通知。
先只贴go源代码了,改天有空我看看是不是写个使用说明。
调用格式是 ./ovh -token=tg机器人的token -chatid=自己tg号的id
加上-test,会模拟加拿大有货,给tg发条通知。这样检查tg参数对不对。

package main

import (
    "encoding/json"
    "flag"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "net/url"
    "os"
    "strings"
    "time"
)

const apiURL = "https://ca.ovh.com/engine/apiv6/dedicated/server/datacenter/availabilities/?excludeDatacenters=false&planCode=24ska01&server=24ska01"

type Datacenter struct {
    Availability string `json:"availability"`
    Datacenter   string `json:"datacenter"`
}

type Server struct {
    Datacenters []Datacenter `json:"datacenters"`
}

func checkAvailability(testMode bool, telegramBotToken, chatID string) {
    log.Println("Starting availability check...")

    resp, err := http.Get(apiURL)
    if err != nil {
        log.Println("Failed to fetch data:", err)
        return
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Println("Failed to read response body:", err)
        return
    }

    log.Println("Received JSON response:", string(body))

    var servers []Server
    err = json.Unmarshal(body, &servers)
    if err != nil {
        log.Println("Failed to parse JSON:", err)
        return
    }

    // 如果是测试模式,强行设置 bhs 数据中心的可用性为 72H
    if testMode {
        log.Println("Test mode enabled. Forcing bhs datacenter availability to 72H.")
        for i, server := range servers {
            for j, dc := range server.Datacenters {
                if dc.Datacenter == "bhs" {
                    servers[i].Datacenters[j].Availability = "72H"
                }
            }
        }
    }

    for _, server := range servers {
        for _, dc := range server.Datacenters {
            log.Printf("Checking datacenter: %s, availability: %s\n", dc.Datacenter, dc.Availability)
            if dc.Availability != "unavailable" {
                log.Printf("Availability change detected: %s in datacenter: %s\n", dc.Availability, dc.Datacenter)
                sendTelegramNotification(dc.Datacenter, dc.Availability, telegramBotToken, chatID)
                return // 一旦发现可用的服务器,立即发送通知并停止进一步检查
            }
        }
    }

    log.Println("No availability changes detected.")
}

func sendTelegramNotification(datacenter, availability, telegramBotToken, chatID string) {
    msg := fmt.Sprintf("Server availability changed to: %s in datacenter: %s", availability, datacenter)
    telegramApi := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", telegramBotToken)

    log.Printf("Sending notification: %s\n", msg)

    form := url.Values{}
    form.Add("chat_id", chatID)
    form.Add("text", msg)

    resp, err := http.Post(telegramApi, "application/x-www-form-urlencoded", strings.NewReader(form.Encode()))
    if err != nil {
        log.Println("Failed to send telegram message:", err)
        return
    }
    defer resp.Body.Close()

    log.Println("Notification sent successfully.")
}

func main() {
    // 解析命令行参数
    testMode := flag.Bool("test", false, "Enable test mode to simulate availability change")
    telegramBotToken := flag.String("token", "", "Telegram bot token")
    chatID := flag.String("chatid", "", "Telegram chat ID")
    flag.Parse()

    // 检查是否提供了必要的参数
    if *telegramBotToken == "" || *chatID == "" {
        fmt.Println("Usage: ./exename -token=<telegramBotToken> -chatid=<chatID> [-test]")
        os.Exit(1)
    }

    for {
        checkAvailability(*testMode, *telegramBotToken, *chatID)
        time.Sleep(1 * time.Minute)
    }
}

这个脚本是与nginx和Cloudflare配套使用的。在一分钟内累计请求数达到1000时,进入under attack模式10分钟,然后解除。 当然,数值是可以根据情况修改的。
原理很简单,每30秒统计一下nginx的访问日志即可。脚本差不多90%是gpt完成的。
功能很简单,不过nginx和cloudflare居然都没有简单的方法实现这一点。cf的rate limit基本就是个废物。因为现在主流的cc都是多ip低访问量的方式。
因为每30秒钟要扫描一次日志文件,如果访问量很大,这脚本当然就不能用了,不然太消耗资源,一般小网站没问题的。

#!/bin/bash

# 日志文件路径
LOG_FILE="/var/log/nginx/access.log"
CHECK_LOG="/var/log/nginx/check.log"  # 输出日志文件路径

# Cloudflare API 相关信息
ZONE_ID="xxxxxxxxxxxxxxxx"  # Cloudflare Zone ID
EMAIL="xxxxxxxxxxx"  # Cloudflare 登录邮箱
API_KEY="xxxxxxxxxxxx"  # Cloudflare Global API Key

# 请求阈值和计时
THRESHOLD=1000
COOLDOWN_TIME=10 # Under Attack 模式保持的分钟数

while true; do
    # 统计过去 1 分钟的请求次数
    REQ_COUNT=$(grep "$(date +'%d/%b/%Y:%H:%M')" $LOG_FILE | wc -l)

    # 检查请求数是否超过阈值
    if [ "$REQ_COUNT" -gt "$THRESHOLD" ]; then
        echo "$(date) - Requests in last minute: $REQ_COUNT. Exceeded!" >> $CHECK_LOG
        echo "$(date) - Enabling 'Under Attack' mode." >> $CHECK_LOG
        
        # 启用 Cloudflare "Under Attack" 模式
        curl -s -o /dev/null -X PATCH "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/settings/security_level" \
            -H "X-Auth-Email: $EMAIL" \
            -H "X-Auth-Key: $API_KEY" \
            -H "Content-Type: application/json" \
            --data '{"value":"under_attack"}'
        
        # 等待 10 分钟后关闭 "Under Attack" 模式
        sleep "${COOLDOWN_TIME}m"
        
        # 取消 Cloudflare "Under Attack" 模式
        curl -s -o /dev/null -X PATCH "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/settings/security_level" \
            -H "X-Auth-Email: $EMAIL" \
            -H "X-Auth-Key: $API_KEY" \
            -H "Content-Type: application/json" \
            --data '{"value":"medium"}'
        
        echo "$(date) - 'Under Attack' mode disabled." >> $CHECK_LOG
    else
        echo "$(date) - Requests in last minute: $REQ_COUNT. No action needed." >> $CHECK_LOG
    fi

    # 等待 30s再检查
    sleep 30
done