4 คะแนน โดย GN⁺ 2024-01-17 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • Speedbump คือ TCP proxy ที่เขียนด้วย Go ซึ่งเพิ่ม network latency แบบปรับเปลี่ยนได้ให้กับ TCP traffic ที่ถูก proxy เพื่อจำลองสถานการณ์ความหน่วง
  • สามารถเพิ่มองค์ประกอบ latency ในรูปแบบ คลื่นไซน์, คลื่นฟันเลื่อย, คลื่นสี่เหลี่ยม, คลื่นสามเหลี่ยม เข้าไปใน latency พื้นฐานได้ และสามารถผสมองค์ประกอบ latency หลายแบบพร้อมกันได้
  • ตัวอย่างแสดงคอนฟิกที่ proxy traffic ไปยัง localhost:80 ผ่านพอร์ต 2000 พร้อมกำหนด latency พื้นฐาน 100ms, แอมพลิจูดคลื่นไซน์ 100ms และคาบ 1m
  • การติดตั้งทำได้ด้วยการดาวน์โหลดไบนารีที่ build ไว้ล่วงหน้าตามแต่ละ release, ใช้ go build จากซอร์ส หรือรัน container image kffl/speedbump
  • นอกจาก CLI แล้วยังสามารถใช้เป็น library ผ่านแพ็กเกจ lib ของ Go ได้ และปรับขนาดบัฟเฟอร์, ขนาดคิวหน่วงเวลา, log level, host และ port สำหรับ listen ฯลฯ ผ่านอาร์กิวเมนต์ได้

Proxy สำหรับจำลองความหน่วง TCP

  • Speedbump คือ TCP proxy ที่เขียนด้วย Go และสามารถจำลอง network latency แบบปรับเปลี่ยนได้
  • เป้าหมายที่จะ proxy ระบุด้วยอาร์กิวเมนต์ <destination> ของ CLI โดยระบุรูปแบบไว้เป็น host:post
  • การทำงานพื้นฐานคือ proxy TCP traffic ไปยังปลายทางพร้อมเพิ่มความหน่วงตามที่ตั้งค่าไว้

วิธีติดตั้งและรัน

  • วิธีติดตั้งที่ง่ายที่สุดคือดาวน์โหลด ไบนารีที่ build ไว้ล่วงหน้า ซึ่งแนบอัตโนมัติใน Assets ของแต่ละ release
  • หากต้องการ build จากซอร์ส ให้ clone repository แล้วรัน go build
  • หากต้องการรันด้วย container สามารถใช้อิมเมจ kffl/speedbump ได้

ตัวอย่างการใช้งานพื้นฐาน

  • สามารถ listen ที่พอร์ต 2000 และ proxy TCP traffic ไปยัง localhost:80 พร้อมใช้ความหน่วงพื้นฐาน 100ms, แอมพลิจูดคลื่นไซน์ 100ms และคาบ 1m
    • คอนฟิกนี้ทำให้เกิด latency เพิ่มเติมสูงสุด 200ms และ latency เพิ่มเติมต่ำสุด 0
    • ตัวอย่างการรันคือ speedbump --latency=100ms --sine-amplitude=100ms --sine-period=1m --port=2000 localhost:80
  • สามารถรันคอนฟิกเดียวกันด้วย container image ได้เช่นกัน
    • ตัวอย่างคือ docker run --net=host kffl/speedbump:latest --latency=100ms --sine-amplitude=100ms --sine-period=1m --port=2000 localhost:80
  • สามารถตั้งค่าองค์ประกอบความหน่วงแบบคลื่นฟันเลื่อยได้ด้วย
    • ตัวอย่างคือคอนฟิก latency พื้นฐาน 300ms, แอมพลิจูดคลื่นฟันเลื่อย 200ms, คาบ 2m, พอร์ต 2000, ปลายทาง localhost:80
    • คำสั่งรันคือ speedbump --latency=300ms --saw-amplitude=200ms --saw-period=2m --port=2000 localhost:80

การผสมองค์ประกอบ latency

  • Speedbump สามารถใช้องค์ประกอบ latency หลายแบบพร้อมกันได้
  • README มีตัวอย่างกราฟความหน่วงที่ผสมคลื่นฟันเลื่อยกับคลื่นไซน์

อาร์กิวเมนต์ CLI และการใช้งานเป็น library

  • speedbump --help แสดงวิธีใช้ในรูปแบบ speedbump [<flags>] <destination>
  • การตั้งค่าเครือข่ายหลักมีดังนี้
    • --host: IP หรือ hostname ที่จะ listen หากไม่ระบุจะ bind กับทุก network interface
    • --port: พอร์ตที่ listen ค่าเริ่มต้นคือ 8000
    • --buffer: ขนาดบัฟเฟอร์ที่ใช้สำหรับอ่าน TCP ค่าเริ่มต้นคือ 64KB
    • --queue-size: ขนาดคิวหน่วงเวลาที่เก็บบัฟเฟอร์อ่าน ค่าเริ่มต้นคือ 1024
  • มีค่าเริ่มต้นที่เกี่ยวกับความหน่วงและตัวเลือก waveform
    • --latency: latency พื้นฐานที่เพิ่มให้กับ traffic ที่ถูก proxy ค่าเริ่มต้นคือ 5ms
    • --sine-amplitude, --sine-period: แอมพลิจูดและคาบของ latency แบบคลื่นไซน์
    • --saw-amplitude, --saw-period: แอมพลิจูดและคาบของ latency แบบคลื่นฟันเลื่อย
    • --square-amplitude, --square-period: แอมพลิจูดและคาบของ latency แบบคลื่นสี่เหลี่ยม
    • --triangle-amplitude, --triangle-period: แอมพลิจูดและคาบของ latency แบบคลื่นสามเหลี่ยม
  • รวมถึงตัวเลือกด้านการปฏิบัติการ
    • --log-level: ระดับ log โดยค่าที่ใช้ได้คือ DEBUG, TRACE, INFO, WARN, ERROR
    • --version: แสดงเวอร์ชันของแอปพลิเคชัน
  • Speedbump สามารถใช้เป็น library ของ Go ได้ด้วย โดยให้ผ่านแพ็กเกจ lib
  • License คือ Apache 2.0 License

1 ความคิดเห็น

 
GN⁺ 2024-01-17
ความคิดเห็นบน Hacker News
  • ผมเคยลองมองหาอะไรคล้าย ๆ กันเพื่อทดสอบ ActivityPub implementation หลายตัวในสเกลและเงื่อนไขเครือข่ายที่ต่างกัน แต่กลายเป็นว่าในเครื่องผมมีทุกอย่างที่ต้องใช้ติดตั้งอยู่แล้วผ่าน tc
    บนดิสโทรของผมมันอยู่ในแพ็กเกจ iproute2 และมีคำอธิบายอยู่ที่นี่ด้วย: https://wiki.archlinux.org/title/advanced_traffic_control
    ถ้าจะเพิ่มดีเลย์ให้กับอินเทอร์เฟซหนึ่ง ๆ ก็รันประมาณ tc qdisc add dev eth0 root netem delay 100ms
    ใช้ง่าย ทำงานได้ดีใน Docker container ด้วย และสามารถใส่เงื่อนไขอย่างดีเลย์ แพ็กเก็ตสูญหาย แพ็กเก็ตซ้ำ ฯลฯ ได้ แถมอาจติดตั้งอยู่แล้วก็ได้

    • tc/netem/tbf ดีมากจริง ๆ ผมเคยทำ Python GUI ง่าย ๆ ครอบมัน แล้วรันบน Pi ที่ใส่เคสจอสัมผัสไว้ เป็นกล่องดำเล็ก ๆ ที่มีปุ่มอย่าง “ดรอปแพ็กเก็ต: [0%] [1%] [10%] [50%] / ทำให้แพ็กเก็ตเสียหาย: ...” ลูกค้าค่อนข้างทึ่งเลย
      น่าแปลกที่ไม่ค่อยเห็นฟรอนต์เอนด์แบบเดียวกันในรูปสินค้า hardware เชิงพาณิชย์ ถ้าผมไม่ได้ค้นพลาด ก็ดูเหมือนตลาดจะยังไม่มี
    • ข้อเสียของ tc คือถ้าจะใช้กับ แพ็กเก็ตขาเข้า จะค่อนข้างแปลกและยุ่งยาก
      เมื่อก่อนผมเคยทำอีมูเลเตอร์เองเพื่อเลียนแบบเทอร์มินัลดาวเทียมเชิงพาณิชย์บางรุ่น เทอร์มินัลนั้นจะคิวแพ็กเก็ตไว้ แล้วเมื่อถึง threshold บางอย่างหรือเกิน timeout ก็จะปล่อยออกมาเป็นก้อน และมันพยายาม “ใจดี” ด้วยการจัดเรียงแพ็กเก็ตเล็ก ๆ ไปไว้หน้าคิวเพื่อลด latency แต่ TCP stack ไม่ชอบแบบนั้นมาก ๆ
    • จุดดีของ speedbump คือสามารถ ปรับเงื่อนไขความขัดข้องตามเวลา ได้ แต่ tc ทำแบบนั้นไม่ได้
      น่าจะมีประโยชน์พอสมควรในการจำลองผลกระทบจากสภาพอากาศของดาวเทียม/RF ที่เปลี่ยนไปตามเวลา
  • สิ่งที่ Netflix ทำก็คืออันนี้เลย ชื่อว่า latency monkey
    พวกเขาพบว่าการตัดสินว่า service ย่อย “ช้า” หรือไม่นั้นยากกว่าการตัดสินว่า “ใช้ไม่ได้” มาก และมันจึงเป็นวิธีสำคัญในการทดสอบว่า service รับมือกับการช้าลงและปัญหาเครือข่ายอย่างไร
    implementation นั้นเรียบง่ายมาก คือดรอปแพ็กเก็ตตามสัดส่วนที่ตั้งค่าได้ ซึ่งจะบังคับให้มีการ retransmit ทำให้อีกฝั่งได้รับแพ็กเก็ตล่าช้าและลำดับสลับกัน
    สุดท้ายก็เจอปัญหามากมายใน โค้ดจัดการ error ที่เกี่ยวกับการเข้าถึงเครือข่าย

  • ผมคิดว่า software engineer ทุกคนที่สร้างแอปอินเทอร์เน็ตแบบ interactive ควรใช้เครื่องมือแบบนี้เป็นประจำในงานประจำวัน ไม่ใช่แค่ TCP แต่ควรมี QUIC ด้วย และถ้าจะครอบ DNS ให้ได้ อุดมคติคือควรรวม UDP ทั้งหมดด้วย
    ผมมั่นใจว่า 90% ของการบวมเกินจำเป็นของเว็บแอปคงหายไป ถ้าคนสร้างไม่ได้ใช้แต่สภาพแวดล้อมคอมพิวติ้งแบบ Cadillac ชุบทอง

    • Firefox Developer Tools ก็ทำสิ่งนี้ได้ Chrome Developer Tools ก็น่าจะมีฟีเจอร์คล้ายกัน
      https://firefox-source-docs.mozilla.org/devtools-user/networ...
      แน่นอนว่านี่ใช้ได้เฉพาะการทดสอบฝั่งฟรอนต์เอนด์ที่อิงเบราว์เซอร์เท่านั้น
  • แอปจำนวนมากทำงานได้แย่มากในสภาพแวดล้อมที่การเชื่อมต่อเครือข่าย หลุดเป็นช่วง ๆ เช่น สถานการณ์บรรเทาภัยพิบัติ
    ถ้านักพัฒนาแอปมากขึ้นจำลองและทดสอบการเชื่อมต่อแบบติด ๆ ดับ ๆ ก็น่าจะช่วยคนอื่นได้
    จาก “Toxiproxy is a framework for simulating network conditions” (2021) https://news.ycombinator.com/item?id=29084277#29088775:

    แอปจำนวนมากไม่มีฟีเจอร์อย่าง ‘พักไว้ในกล่องขาออก’ ที่เราคาดหวังจากไคลเอนต์อีเมล

    • [ ] ใครสักคนจะสร้างชุด toxiproxy ‘ตัวแปร test case’ สำหรับอ้างอิงที่จำลองปัญหาการเชื่อมต่อทั่วไปของ #DisasterRelief ได้ไหม?
    • สิ่งที่ผมเกลียดที่สุดคือกรณีที่ ไม่เติมบัฟเฟอร์ให้เต็ม ก่อนส่งแพ็กเก็ต พออยู่กับการเชื่อมต่ออินเทอร์เน็ตแย่ ๆ คือมีแพ็กเก็ตดรอปและ latency สูงจนเกิด TCP retransmission ก็เหลือ throughput แค่ 120kps ทันที
      เพราะกำลังส่งแต่แพ็กเก็ตขนาด 50 ไบต์ และในนั้นหายไป 1 ใน 10 ระหว่างนั้น thread หนึ่งของเซิร์ฟเวอร์ก็ไม่ได้ทำงานที่มีประโยชน์อะไรเลย
  • บน Mac ใช้แค่เครื่องมือที่มีมาให้ก็ทำแบบเดียวกันได้

    # Setup pipe  
    sudo dnctl pipe 1 config bw 1Kbit/s delay 800
    
    # Setup matching pf rule  
    echo "dummynet out proto tcp from any to 127.0.0.1 port 11211 pipe 1" | sudo pfctl -f -
    
    # Turn on firewall  
    sudo pfctl -e
    
    # Test  
    time nc -vz 127.0.0.1 11211  
    Connection to 127.0.0.1 port 11211 [tcp/*] succeeded!  
    nc -vz 127.0.0.1 11211 0.01s user 0.00s system 0% cpu 1.333 total  
    
    • Dummynet และฟีเจอร์เหล่านี้มาจาก FreeBSD และมีอยู่ที่นั่นมานานแล้ว ผมเคยใช้ทดสอบ packet loss เมื่อกว่า 15 ปีก่อน และมันก็ทำงานได้ดี
  • มีโปรเจกต์หนึ่งที่ไม่ได้ active มาสักพักแล้ว แต่แค่ชื่อก็บอกอะไรได้มาก: https://github.com/tylertreat/comcast

  • เมื่อไม่นานมานี้ผมพยายามจำลองเครือข่ายช้าบน Mac แล้วเจอ Network Link Conditioner ซึ่งค่อนข้างดี ไม่ต้องตั้งค่า proxy อะไรเลย
    ต้องติดตั้งจากเครื่องมือเพิ่มเติมของ Xcode
    https://nshipster.com/network-link-conditioner/

  • เครื่องมือยอดเยี่ยมของ Shopify อย่าง toxiproxy ก็น่าดู: https://github.com/Shopify/toxiproxy
    นี่ยังเป็นวิธีที่ดีมากในการทดสอบ networking library ที่คุณ implement เองด้วย เพราะ stack ควรรับมือกับสถานการณ์เลวร้ายส่วนใหญ่ได้อย่างถูกต้อง
    แนวคิดเรื่อง ‘chaos engineering’ นั้นเจ๋งดี

    • ตอนแรกผมก็หา toxiproxy เหมือนกัน แต่โมเดล client-server ไม่เหมาะกับผม และ speedbump ตรงกับ use case ของผมในการจำลอง HTTP delay พอดี
      ผมกำลังพัฒนา progress bar สำหรับเว็บครอว์เลอร์ แต่ถ้าทดสอบบน localhost มันเร็วเกินไปจนดูยากว่ามีปัญหาหรือเปล่า
      พอใช้ speedbump ก็แค่รัน podman run --net=host kffl/speedbump:latest --latency=1s --port=8001 localhost:8000 แล้วทดสอบครอว์เลอร์ที่ http://localhost:8001 ได้เลย
      เป็นเครื่องมือที่เรียบร้อยดี
  • มีเครื่องมือคล้าย ๆ กันที่ผมเคยใช้บน Windows
    https://jagt.github.io/clumsy/

    • ผมใช้เมื่อราว 10 ปีก่อนเพื่อทดสอบ สภาพเครือข่ายข้ามทวีป หลายแบบ และผลลัพธ์ก็ตรงกับความเป็นจริงดี แนะนำได้
    • ดูเจ๋งดี แต่จาก screenshot อย่างเดียว ดูเหมือนจะเป็นการใช้กับ ทั้งระบบพร้อม filter มากกว่าจะใช้แยกตาม adapter
  • FreeBSD ก็มี dummynet เป็นส่วนหนึ่งของ ipfw ซึ่งสามารถฉีด delay, จำกัด bandwidth, กำหนด queue size และ packet loss ได้ เป็นฟีเจอร์เดียวกับที่มีบน MacOS

    • เหมือนกับ tc บน Linux หรือเปล่า?