Dokumen ini membahas cara menggunakan Load Balancer Jaringan passthrough eksternal dengan menggunakan User Datagram Protocol (UDP). Dokumen ini ditujukan untuk developer aplikasi, operator aplikasi, dan administrator jaringan.
Tentang UDP
UDP umum digunakan di aplikasi. Protokol, yang dijelaskan dalam RFC-768, menerapkan layanan paket datagram yang stateless dan tidak andal. Misalnya, protokol QUIC Google meningkatkan pengalaman pengguna dengan menggunakan UDP untuk mempercepat aplikasi berbasis streaming.
Bagian UDP yang stateless berarti lapisan transport tidak mempertahankan status. Oleh karena itu, setiap paket dalam "koneksi" UDP bersifat independen. Sebenarnya,
tidak ada koneksi nyata di UDP. Sebagai gantinya, pesertanya biasanya menggunakan
2-tuple (ip:port) atau 4-tuple (src-ip:src-port, dest-ip:dest-port) untuk
saling mengenali.
Seperti aplikasi berbasis TCP, aplikasi berbasis UDP juga dapat memanfaatkan load balancer, itulah sebabnya Load Balancer Jaringan passthrough eksternal digunakan dalam skenario UDP.
Load Balancer Jaringan passthrough eksternal
Load Balancer Jaringan passthrough eksternal adalah load balancer passthrough; load balancer ini memproses paket masuk dan mengirimkannya ke server backend dengan paket tetap utuh. Server backend kemudian mengirimkan paket yang kembali langsung ke klien. Teknik ini disebut Direct Server Return (DSR). Di setiap virtual machine (VM) Linux yang berjalan di Compute Engine yang merupakan backend dari Load Balancer Jaringan passthrough eksternalGoogle Cloud , entri di tabel pemilihan rute lokal akan merutekan traffic yang ditujukan ke alamat IP load balancer ke pengontrol antarmuka jaringan (NIC). Contoh berikut menunjukkan teknik ini:
root@backend-server:~# ip ro ls table local
local 10.128.0.2 dev eth0 proto kernel scope host src 10.128.0.2
broadcast 10.128.0.2 dev eth0 proto kernel scope link src 10.128.0.2
local 198.51.100.2 dev eth0 proto 66 scope host
broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
Dalam contoh sebelumnya, 198.51.100.2 adalah alamat IP load balancer. Agen
google-network-daemon.service bertanggung jawab untuk menambahkan entri ini.
Namun, seperti yang ditunjukkan contoh berikut, VM sebenarnya tidak memiliki antarmuka yang memiliki alamat IP load balancer:
root@backend-server:~# ip ad ls
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1460 qdisc mq state UP group default qlen 1000
link/ether 42:01:0a:80:00:02 brd ff:ff:ff:ff:ff:ff
inet 10.128.0.2/32 brd 10.128.0.2 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::4001:aff:fe80:2/64 scope link
valid_lft forever preferred_lft forever
Load Balancer Jaringan passthrough eksternal mengirimkan paket masuk, dengan alamat tujuan tidak diubah, ke server backend. Entri tabel perutean lokal merutekan paket ke proses aplikasi yang benar, dan paket respons dari aplikasi dikirim langsung ke klien.
Diagram berikut menunjukkan cara kerja Load Balancer Jaringan passthrough eksternal. Paket masuk diproses oleh load balancer yang disebut Maglev, yang mendistribusikan paket ke server backend. Paket keluar kemudian dikirim langsung ke klien melalui DSR.
Masalah terkait paket kembali UDP
Saat Anda bekerja dengan DSR, ada sedikit perbedaan antara cara kernel Linux memperlakukan koneksi TCP dan UDP. Karena TCP adalah protokol stateful, kernel memiliki semua informasi yang diperlukan tentang koneksi TCP, termasuk alamat klien, port klien, alamat server, dan port server. Informasi ini dicatat dalam struktur data soket yang merepresentasikan koneksi. Dengan demikian, setiap paket yang kembali dari koneksi TCP memiliki alamat sumber yang disetel dengan benar ke alamat server. Untuk load balancer, alamat tersebut adalah alamat IP load balancer.
Ingatlah bahwa UDP tidak memiliki status, sehingga objek soket yang dibuat dalam proses aplikasi untuk koneksi UDP tidak memiliki informasi koneksi. Kernel tidak memiliki informasi tentang alamat sumber paket keluar, dan tidak mengetahui hubungannya dengan paket yang diterima sebelumnya. Untuk alamat sumber paket, kernel hanya dapat mengisi alamat antarmuka yang dituju paket UDP yang dikembalikan. Atau jika aplikasi sebelumnya mengikat soket ke alamat tertentu, kernel menggunakan alamat tersebut sebagai alamat sumber.
Kode berikut menunjukkan program echo sederhana:
#!/usr/bin/python3
import socket,struct
def loop_on_socket(s):
while True:
d, addr = s.recvfrom(1500)
print(d, addr)
s.sendto("ECHO: ".encode('utf8')+d, addr)
if __name__ == "__main__":
HOST, PORT = "0.0.0.0", 60002
sock = socket.socket(type=socket.SocketKind.SOCK_DGRAM)
sock.bind((HOST, PORT))
loop_on_socket(sock)
Berikut adalah output tcpdump selama percakapan UDP:
14:50:04.758029 IP 203.0.113.2.40695 > 198.51.100.2.60002: UDP, length 3 14:50:04.758396 IP 10.128.0.2.60002 > 203.0.113.2.40695: UDP, length 2T
198.51.100.2 adalah alamat IP load balancer, dan 203.0.113.2 adalah alamat IP klien.
Setelah paket meninggalkan VM, perangkat NAT lain–gateway Compute Engine–di jaringan Google Cloud akan menerjemahkan alamat sumber ke alamat eksternal. Gateway tidak mengetahui alamat eksternal mana yang harus digunakan, sehingga hanya alamat eksternal VM (bukan load balancer) yang dapat digunakan.
Dari sisi klien, jika Anda memeriksa output dari tcpdump, paket dari
server akan terlihat seperti berikut:
23:05:37.072787 IP 203.0.113.2.40695 > 198.51.100.2.60002: UDP, length 5 23:05:37.344148 IP 198.51.100.3.60002 > 203.0.113.2.40695: UDP, length 4
198.51.100.3 adalah alamat IP eksternal VM.
Dari sudut pandang klien, paket UDP tidak berasal dari alamat yang dituju oleh klien. Hal ini menyebabkan masalah: kernel akan membuang paket-paket ini, dan jika klien berada di belakang perangkat NAT, perangkat NAT juga akan membuangnya. Akibatnya, aplikasi klien tidak mendapatkan respons dari server. Diagram berikut menunjukkan proses ini saat klien menolak paket yang dikembalikan karena alamat tidak cocok.
Menyelesaikan masalah UDP
Untuk mengatasi masalah tidak ada respons, Anda harus menulis ulang alamat sumber paket keluar ke alamat IP load balancer di server yang menghosting aplikasi. Berikut beberapa opsi yang dapat Anda gunakan untuk melakukan penulisan ulang header ini. Solusi pertama menggunakan pendekatan berbasis Linux dengan iptables;
solusi lainnya menggunakan pendekatan berbasis aplikasi.
Diagram berikut menunjukkan ide inti dari opsi ini: menulis ulang alamat IP sumber paket yang kembali agar cocok dengan alamat IP load balancer.
Menggunakan kebijakan NAT di server backend
Solusi kebijakan NAT adalah menggunakan perintah iptables Linux untuk menulis ulang alamat tujuan dari alamat IP load balancer ke alamat IP VM.
Dalam contoh berikut, Anda menambahkan aturan DNAT iptables untuk mengubah
alamat tujuan paket masuk:
iptables -t nat -A POSTROUTING -j RETURN -d 10.128.0.2 -p udp --dport 60002
iptables -t nat -A PREROUTING -j DNAT --to-destination 10.128.0.2 -d 198.51.100.2 -p udp --dport 60002
Perintah ini menambahkan dua aturan ke tabel NAT sistem iptables. Aturan pertama melewati semua paket masuk yang menargetkan alamat eth0 lokal.
Akibatnya, traffic yang tidak berasal dari load balancer tidak terpengaruh.
Aturan kedua mengubah alamat IP tujuan paket masuk menjadi alamat IP internal VM. Aturan DNAT bersifat stateful, yang berarti bahwa
kernel melacak koneksi dan menulis ulang alamat sumber paket yang kembali
secara otomatis.
| Kelebihan | Kekurangan |
|---|---|
| Kernel menerjemahkan alamat, tanpa perlu perubahan pada aplikasi. | CPU tambahan digunakan untuk melakukan NAT. Dan karena DNAT bersifat stateful, konsumsi memori juga mungkin tinggi. |
| Mendukung beberapa load balancer. |
Gunakan nftables untuk memanipulasi kolom header IP secara stateless
Dalam solusi nftables, Anda menggunakan perintah nftables untuk memanipulasi alamat sumber di header IP paket keluar. Pengubahan ini tidak memiliki status, sehingga
menggunakan lebih sedikit resource daripada menggunakan DNAT. Untuk menggunakan nftables, Anda memerlukan versi kernel Linux yang lebih baru dari 4.10.
Anda menggunakan perintah berikut:
nft add table raw
nft add chain raw postrouting {type filter hook postrouting priority 300)
nft add rule raw postrouting ip saddr 10.128.0.2 udp sport 60002 ip saddr set 198.51.100.2
| Kelebihan | Kekurangan |
|---|---|
| Kernel menerjemahkan alamat, tanpa perlu perubahan pada aplikasi. | Tidak mendukung beberapa load balancer. |
| Proses terjemahan alamat tidak memiliki status, sehingga konsumsi resource jauh lebih rendah. | CPU tambahan digunakan untuk melakukan NAT. |
nftables hanya tersedia untuk versi kernel Linux yang lebih baru. Beberapa distro, seperti Centos 7.x, tidak dapat menggunakan
nftables.
|
Izinkan aplikasi terikat secara eksplisit ke alamat IP load balancer
Dalam solusi pengikatan, Anda mengubah aplikasi agar terikat secara eksplisit ke
alamat IP load balancer. Untuk soket UDP, operasi bind memungkinkan
kernel mengetahui alamat mana yang akan digunakan sebagai alamat sumber saat mengirim paket UDP
yang menggunakan soket tersebut.
Contoh berikut menunjukkan cara mengikat ke alamat tertentu di Python:
#!/usr/bin/python3
import socket
def loop_on_socket(s):
while True:
d, addr = s.recvfrom(1500)
print(d, addr)
s.sendto("ECHO: ".encode('utf8')+d, addr)
if __name__ == "__main__":
# Instead of setting HOST to "0.0.0.0",
# we set HOST to the Load Balancer IP
HOST, PORT = "198.51.100.2", 60002
sock = socket.socket(type=socket.SocketKind.SOCK_DGRAM)
sock.bind((HOST, PORT))
loop_on_socket(sock)
# 198.51.100.2 is the load balancer's IP address
# You can also use the DNS name of the load balancer's IP address
Kode sebelumnya adalah server UDP; kode ini mengembalikan byte yang diterima, dengan "ECHO: " sebelumnya. Perhatikan baris 12 dan 13, tempat server
terikat ke alamat 198.51.100.2, yang merupakan alamat IP load balancer.
| Kelebihan | Kekurangan |
|---|---|
| Dapat dicapai dengan perubahan kode sederhana pada aplikasi. | Tidak mendukung beberapa load balancer. |
Gunakan recvmsg/sendmsg, bukan recvfrom/sendto untuk menentukan alamat
Dalam solusi ini, Anda menggunakan panggilan recvmsg/sendmsg, bukan panggilan recvfrom/sendto. Jika dibandingkan dengan panggilan recvfrom/sendto, panggilan
recvmsg/sendmsg dapat menangani pesan kontrol tambahan bersama dengan
data payload. Pesan kontrol tambahan ini mencakup alamat sumber atau tujuan paket. Solusi ini memungkinkan Anda mengambil alamat tujuan dari
paket masuk, dan karena alamat tersebut adalah alamat load balancer
yang sebenarnya, Anda dapat menggunakannya sebagai alamat sumber saat mengirim balasan.
Contoh program berikut menunjukkan solusi ini:
#!/usr/bin/python3
import socket,struct
def loop_on_socket(s):
while True:
d, ctl, flg, addr = s.recvmsg(1500, 1024)
# ctl contains the destination address information
s.sendmsg(["ECHO: ".encode("utf8"),d], ctl, 0, addr)
if __name__ == "__main__":
HOST, PORT = "0.0.0.0", 60002
s = socket.socket(type=socket.SocketKind.SOCK_DGRAM)
s.setsockopt(0, # level is 0 (IPPROTO_IP)
8, # optname is 8 (IP_PKTINFO)
1)
s.bind((HOST, PORT))
loop_on_socket(s)
Program ini menunjukkan cara menggunakan panggilan recvmsg/sendmsg. Untuk mengambil informasi alamat dari paket, Anda harus menggunakan panggilan setsockopt untuk menetapkan opsi IP_PKTINFO.
| Kelebihan | Kekurangan |
|---|---|
| Berfungsi meskipun ada beberapa load balancer–misalnya, saat ada load balancer internal dan eksternal yang dikonfigurasi ke backend yang sama. | Memerlukan Anda untuk membuat perubahan yang kompleks pada aplikasi. Dalam beberapa kasus, hal ini mungkin tidak dapat dilakukan. |
Langkah berikutnya
- Pelajari cara mengonfigurasi Load Balancer Jaringan passthrough eksternal dan mendistribusikan traffic di Menyiapkan Load Balancer Jaringan passthrough eksternal.
- Baca lebih lanjut Load Balancer Jaringan passthrough eksternal.
- Baca lebih lanjut teknik Maglev di balik Load Balancer Jaringan passthrough eksternal.