Dokumen ini membahas cara bekerja dengan Load Balancer Jaringan passthrough eksternal menggunakan Protokol Datagram Pengguna (UDP). Dokumen ini ditujukan untuk developer aplikasi, operator aplikasi, dan administrator jaringan.
Tentang UDP
UDP biasanya digunakan dalam aplikasi. Protokol yang dijelaskan dalam RFC-768, menerapkan layanan paket datagram stateless dan tidak dapat diandalkan. Misalnya, protokol QUIC Google meningkatkan pengalaman pengguna dengan menggunakan UDP untuk mempercepat aplikasi berbasis streaming.
Bagian stateless dari UDP berarti bahwa lapisan transpor tidak mempertahankan status. Oleh karena itu, setiap paket dalam "koneksi" UDP bersifat independen. Faktanya, tidak ada koneksi
nyata dalam UDP. Sebagai gantinya, peserta biasanya menggunakan
2 tuple (ip:port
) atau 4 tuple (src-ip:src-port
, dest-ip:dest-port
) untuk
mengenali satu sama lain.
Seperti aplikasi berbasis TCP, aplikasi berbasis UDP juga dapat memperoleh manfaat dari 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 tersebut memproses paket yang masuk dan mengirimkannya ke server backend bersama paket tersebut. Selanjutnya, server backend akan mengirim 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 perutean 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 ditampilkan dalam 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 yang tidak disentuh, 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 akan 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 yang ditampilkan 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 merepresentasikan 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, ingatlah 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 hubungan dengan paket yang diterima sebelumnya. Untuk alamat sumber paket, kernel hanya dapat mengisi alamat antarmuka yang menjadi tujuan paket UDP yang ditampilkan. Atau, jika aplikasi sebelumnya mengaitkan soket ke alamat tertentu, kernel akan menggunakan alamat tersebut sebagai alamat sumber.
Kode berikut menunjukkan program {i>echo<i} 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–gateway Compute Engine–di jaringan Google Cloud menerjemahkan alamat sumber ke alamat eksternal. Gateway tidak mengetahui alamat eksternal mana yang harus digunakan, sehingga hanya alamat eksternal VM (bukan alamat 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 menjadi tujuan pengiriman klien. Hal ini menyebabkan masalah: kernel menghapus paket ini, dan jika klien berada di belakang perangkat NAT, perangkat NAT juga akan terinstal. Akibatnya, aplikasi klien tidak mendapat respons dari server. Diagram berikut menunjukkan proses ini saat klien menolak paket yang ditampilkan karena alamat tidak cocok.
Menyelesaikan masalah UDP
Untuk mengatasi masalah tanpa respons, Anda harus menulis ulang alamat sumber
paket keluar ke alamat IP load balancer di server yang menghosting
aplikasi. Berikut adalah beberapa opsi yang dapat Anda gunakan untuk menyelesaikan
penulisan ulang header ini. Solusi pertama menggunakan pendekatan berbasis Linux dengan iptables
;
solusi lainnya mengambil pendekatan berbasis aplikasi.
Diagram berikut menunjukkan ide inti dari opsi ini: menulis ulang alamat IP sumber dari 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.
Pada 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 --dport 60002 -p udp
Perintah ini menambahkan dua aturan ke tabel NAT sistem iptables
. Aturan pertama mengabaikan semua paket masuk yang menargetkan alamat eth0
lokal.
Oleh karena itu, traffic yang tidak berasal dari load balancer tidak akan terpengaruh.
Aturan kedua mengubah alamat IP tujuan paket masuk ke
alamat IP internal VM. Aturan DNAT bersifat stateful, yang berarti bahwa
kernel melacak koneksi dan menulis ulang alamat sumber paket yang ditampilkan
secara otomatis.
Kelebihan | Kekurangan |
---|---|
Kernel menerjemahkan alamat, tanpa perlu mengubah aplikasi. | CPU ekstra digunakan untuk melakukan NAT. Dan karena DNAT bersifat stateful, konsumsi memori mungkin juga tinggi. |
Mendukung beberapa load balancer. |
Menggunakan nftables
untuk merusak kolom header IP secara stateless
Dalam solusi nftables
, Anda menggunakan perintah nftables
untuk merusak alamat sumber di header IP paket keluar. Kerusakan ini bersifat stateless, sehingga
menggunakan lebih sedikit resource daripada menggunakan DNAT. Untuk menggunakan nftables
, Anda memerlukan versi kernel Linux yang lebih tinggi dari 4.10.
Anda dapat 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 mengubah aplikasi. | Tidak mendukung beberapa load balancer. |
Proses penerjemahan 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 .
|
Mengizinkan aplikasi secara eksplisit mengikat ke alamat IP load balancer
Dalam solusi binding ini, Anda perlu 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 menggemakan kembali 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 dilakukan 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 masuk, dan karena alamat tersebut adalah alamat load balancer
sebenarnya, Anda dapat menggunakannya sebagai alamat sumber saat mengirim balasan.
Contoh program berikut menunjukkan solusi tersebut:
#!/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. | Mengharuskan Anda untuk membuat 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 artikel 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.