Dokumen ini membahas cara menggunakan Load Balancer Jaringan passthrough eksternal menggunakan User Datagram Protocol (UDP). Dokumen ini ditujukan untuk developer aplikasi, operator aplikasi, dan administrator jaringan.
Tentang UDP
UDP biasanya digunakan di aplikasi. Protokol ini, yang dijelaskan dalam RFC-768, mengimplementasikan layanan paket datagram stateless yang tidak dapat diandalkan. Misalnya, protokol QUIC Google meningkatkan pengalaman pengguna dengan menggunakan UDP untuk mempercepat aplikasi berbasis streaming.
Bagian stateless UDP berarti lapisan transpor tidak mempertahankan
status. Oleh karena itu, setiap paket dalam "koneksi" UDP bersifat independen. Sebenarnya,
tidak ada koneksi yang sebenarnya di UDP. Sebagai gantinya, pesertanya biasanya menggunakan
tuple 2 (ip:port
) atau tuple 4 (src-ip:src-port
, dest-ip:dest-port
) untuk
mengenali satu sama lain.
Seperti aplikasi berbasis TCP, aplikasi berbasis UDP juga dapat memanfaatkan load balancer, yang merupakan alasan 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 yang utuh. Server backend kemudian mengirimkan paket yang ditampilkan 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 eksternal Google Cloud, entri dalam tabel pemilihan rute lokal merutekan traffic yang ditujukan untuk 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
Pada 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 tersentuh, 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 yang 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 return UDP
Saat Anda menggunakan 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 mewakili koneksi. Dengan demikian, setiap paket yang ditampilkan dari koneksi TCP memiliki alamat sumber yang ditetapkan dengan benar ke alamat server. Untuk load balancer, alamat tersebut adalah alamat IP load balancer.
Namun, ingat bahwa UDP bersifat stateless, 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 ditampilkan. Atau, jika aplikasi sebelumnya mengikat soket ke alamat tertentu, kernel akan 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 keluar dari VM, perangkat NAT lain, yaitu 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 klien. Hal ini menyebabkan masalah: kernel akan menghapus paket ini, dan jika klien berada di belakang perangkat NAT, begitu juga dengan perangkat NAT. Akibatnya, aplikasi klien tidak mendapatkan respons dari server. Diagram berikut menunjukkan proses ini saat klien menolak paket yang ditampilkan karena ketidakcocokan alamat.
Memecahkan 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 ditampilkan 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 yang 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 mengabaikan semua paket masuk yang menargetkan alamat eth0
lokal.
Akibatnya, traffic yang tidak berasal dari load balancer tidak akan terpengaruh.
Aturan kedua mengubah alamat IP tujuan paket masuk menjadi alamat IP internal VM. Aturan DNAT bersifat stateful, yang berarti kernel
melacak koneksi dan menulis ulang alamat sumber paket yang ditampilkan
secara otomatis.
Kelebihan | Kekurangan |
---|---|
Kernel menerjemahkan alamat, tanpa memerlukan perubahan pada aplikasi. | CPU tambahan digunakan untuk melakukan NAT. Dan karena DNAT bersifat stateful, konsumsi memori juga mungkin tinggi. |
Mendukung beberapa load balancer. |
Menggunakan nftables
untuk merusak kolom header IP tanpa status
Dalam solusi nftables
, Anda menggunakan perintah nftables
untuk merusak alamat
sumber di header IP paket keluar. Penggabungan ini stateless, sehingga
menggunakan lebih sedikit resource daripada menggunakan DNAT. Untuk menggunakan nftables
, Anda memerlukan versi kernel Linux
yang lebih besar 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 memerlukan perubahan pada aplikasi. | Tidak mendukung beberapa load balancer. |
Proses terjemahan alamat bersifat stateless, 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 secara eksplisit terikat ke alamat IP load balancer
Dalam solusi binding, 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 akan memunculkan kembali byte yang diterima, dengan
"ECHO: "
sebelumnya. Perhatikan baris 12 dan 13, tempat server
diikat 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
. Dibandingkan dengan panggilan recvfrom
/sendto
, panggilan recvmsg
/sendmsg
dapat menangani pesan kontrol tambahan beserta
data payload. Pesan kontrol tambahan ini mencakup alamat sumber atau tujuan
paket. Solusi ini memungkinkan Anda mengambil alamat tujuan dari
paket yang 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 melakukan perubahan kompleks pada aplikasi. Dalam beberapa kasus, hal ini mungkin tidak dapat dilakukan. |
Langkah selanjutnya
- Pelajari cara mengonfigurasi Load Balancer Jaringan passthrough eksternal dan mendistribusikan traffic di Menyiapkan Load Balancer Jaringan passthrough eksternal.
- Baca selengkapnya tentang Load Balancer Jaringan passthrough eksternal.
- Baca selengkapnya tentang teknik Maglev di balik Load Balancer Jaringan passthrough eksternal.