import java.io.*;
import java.net.*;
public class ALBExample {
public static void main(String[] args) {
try {
// 1. 인바운드 요청 수신
int clientPort = 80; // HTTP 포트
ServerSocket serverSocket = new ServerSocket(clientPort);
Socket clientSocket = serverSocket.accept();
// 클라이언트 요청을 읽습니다.
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String clientRequest;
StringBuilder requestBuilder = new StringBuilder();
while ((clientRequest = in.readLine()) != null) {
requestBuilder.append(clientRequest).append("\r\n");
if (clientRequest.isEmpty()) {
break;
}
}
// 클라이언트 요청 내용
String clientRequestContent = requestBuilder.toString();
System.out.println("Received client request:\n" + clientRequestContent);
// 2. 요청 라우팅
String selectedTargetGroup = determineTargetGroup(clientRequestContent);
// 3. 대상 그룹 선택 (여기서는 임의로 선택)
String selectedTarget = selectTarget(selectedTargetGroup);
// 4. 대상 그룹 내에서 로드 밸런싱 (여기서는 임의로 선택)
// 5. HTTP/HTTPS 헤더 조작 (필요한 경우 헤더 조작)
// 6. 응답 반환 (여기서는 간단한 응답을 생성)
String targetResponse = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!";
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
out.write(targetResponse);
out.flush();
// 클라이언트 소켓 및 서버 소켓 닫기
clientSocket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static String determineTargetGroup(String clientRequest) {
// 요청 내용을 분석하여 대상 그룹 선택 로직을 구현
// 여기에서는 단순화한 예제이므로 특정 로직은 구현하지 않습니다.
return "web-servers"; // 예제: 웹 서버 대상 그룹 선택
}
private static String selectTarget(String targetGroup) {
// 대상 그룹 내에서 대상 선택 로직을 구현
// 여기에서는 단순화한 예제이므로 특정 로직은 구현하지 않습니다.
return "web-server-1"; // 예제: 첫 번째 웹 서버 선택
}
}
인바운드 요청 수신: 클라이언트에서 ALB로 HTTP 또는 HTTPS 요청이 도착합니다. 이 요청은 ALB 리스너에 의해 수신됩니다. 리스너는 특정 포트(예: 80 또는 443)에서 대기하고 클라이언트로부터의 연결을 수신합니다.
요청 라우팅: ALB는 요청을 분석하여 어떤 대상 그룹으로 이를 전달할지 결정합니다. 대상 그룹은 서비스된 애플리케이션의 논리적인 구성 단위로, 여러 대상(예: EC2 인스턴스, 컨테이너, IP 주소)을 포함할 수 있습니다.
대상 그룹 선택: ALB는 요청을 처리할 대상 그룹을 선택합니다. 이 선택은 리스너 규칙에 따라 이루어집니다. 리스너 규칙은 요청 경로, 호스트 헤더, HTTP 메소드 및 기타 요청 속성에 따라 대상 그룹을 선택하기 위한 조건을 정의합니다.
대상 그룹 내에서 로드 밸런싱: 선택된 대상 그룹 내에서 ALB는 요청을 여러 대상(예: EC2 인스턴스)으로 분산합니다. 이 과정은 대상 그룹에 등록된 대상들 간에 트래픽이 균등하게 분배되도록 합니다.
HTTP/HTTPS 헤더 조작: ALB는 필요한 경우 HTTP/HTTPS 헤더를 조작하거나 추가할 수 있습니다. 이를 통해 요청을 조작하거나 애플리케이션에 특정 정보를 제공할 수 있습니다.
응답 반환: ALB는 대상 그룹 내의 대상들로부터 받은 응답을 수집하고 클라이언트에게 반환합니다. 이 때 로드 밸런서는 대상의 응답을 재조립하여 클라이언트에게 제공하며, 서버 응답을 클라이언트에게 반환하는 동안 트래픽 로드 밸런싱을 수행합니다.
import java.io.*;
import java.net.*;
public class TCPServerExample {
public static void main(String[] args) {
try {
int serverPort = 8080; // 임의의 포트
ServerSocket serverSocket = new ServerSocket(serverPort);
System.out.println("TCP Server listening on port " + serverPort);
while (true) {
Socket clientSocket = serverSocket.accept();
System.out.println("Accepted incoming TCP connection.");
// 클라이언트 요청을 읽고 처리하는 로직을 추가
// 여기에서는 간단하게 클라이언트에 "Hello, TCP Client!"를 응답으로 보냅니다.
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
out.println("Hello, TCP Client!");
clientSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
ALB를 사용하여 HTTP 트래픽을 수신:
import com.sun.net.httpserver.*;
import java.io.IOException;
import java.io.OutputStream;
public class SimpleHttpServer {
public static void main(String[] args) throws IOException {
int port = 8080; // 임의의 포트
HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
server.createContext("/", new MyHandler());
server.setExecutor(null); // 기본 executor 사용
server.start();
System.out.println("HTTP Server started on port " + port);
}
static class MyHandler implements HttpHandler {
@Override
public void handle(HttpExchange httpExchange) throws IOException {
String response = "Hello, HTTP Client!";
httpExchange.sendResponseHeaders(200, response.length());
OutputStream os = httpExchange.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
}
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class NetworkPacket {
String sourceIP;
String destIP;
int sourcePort;
int destPort;
byte[] data;
// ... 기타 필드와 메서드
}
class BackendServer {
String ip;
public void handlePacket(NetworkPacket packet) {
// 패킷 처리 로직
}
}
class SimpleNLB {
private Map<String, List<BackendServer>> serverPool = new HashMap<>();
public void registerBackend(String ip, BackendServer server) {
serverPool.computeIfAbsent(ip, k -> new ArrayList<>()).add(server);
}
public void distributeTraffic(NetworkPacket packet) {
// NLB는 대상 IP와 포트 정보를 기반으로 패킷을 분산
List<BackendServer> servers = serverPool.get(packet.destIP);
if (servers != null && !servers.isEmpty()) {
// 여기서는 단순히 첫 번째 서버에게 트래픽을 전달합니다.
// 실제 구현에서는 라운드 로빈, 최소 연결 수 등의 알고리즘을 사용할 수 있습니다.
servers.get(0).handlePacket(packet);
}
}
}
public class NLBDemo {
public static void main(String[] args) {
SimpleNLB nlb = new SimpleNLB();
nlb.registerBackend("192.168.0.1", new BackendServer());
nlb.registerBackend("192.168.0.2", new BackendServer());
NetworkPacket packet = new NetworkPacket();
packet.destIP = "192.168.0.1";
nlb.distributeTraffic(packet);
}
}
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
enum Protocol {
TCP, UDP
}
class Packet {
Protocol protocol;
String sourceIP;
String destinationIP;
// ... 기타 필드
}
class Server {
private String ip;
public Server(String ip) {
this.ip = ip;
}
public void handlePacket(Packet packet) {
System.out.println("Handling packet at server: " + ip);
// 패킷 처리 로직
}
}
class NLB {
private String fixedIPAddress; // 고정 IP 주소
private List<Server> servers = new CopyOnWriteArrayList<>();
private AtomicInteger currentServerIndex = new AtomicInteger(0);
public NLB(String fixedIPAddress) {
this.fixedIPAddress = fixedIPAddress;
}
public void addServer(Server server) {
servers.add(server);
}
public void processTraffic(Packet packet) {
distributeTraffic(packet);
}
private void distributeTraffic(Packet packet) {
if (servers.isEmpty()) {
System.out.println("No servers available to handle packet");
return;
}
int index = currentServerIndex.getAndUpdate(i -> (i + 1) % servers.size());
Server selectedServer = servers.get(index);
selectedServer.handlePacket(packet);
}
public String getFixedIPAddress() {
return fixedIPAddress;
}
}
public class NLBDemo {
public static void main(String[] args) {
NLB nlb = new NLB("192.168.1.100"); // 고정 IP 주소
nlb.addServer(new Server("192.168.1.101"));
nlb.addServer(new Server("192.168.1.102"));
nlb.addServer(new Server("192.168.1.103"));
// TCP 트래픽 예제
Packet tcpPacket = new Packet();
tcpPacket.protocol = Protocol.TCP;
// UDP 트래픽 예제
Packet udpPacket = new Packet();
udpPacket.protocol = Protocol.UDP;
nlb.processTraffic(tcpPacket);
nlb.processTraffic(udpPacket);
System.out.println("NLB is processing traffic on IP: " + nlb.getFixedIPAddress());
}
}
어떻게 동작하는가? 이것은 이전 버전의 로드 밸런서로, OSI 계층 4에서 동작합니다. TCP 및 HTTP 트래픽을 로드 밸런싱합니다.
어떻게 동작하는가? ELB는 이전 버전의 AWS 로드 밸런서로, OSI 계층 4에서 동작합니다. TCP 및 HTTP 트래픽을 로드 밸런싱합니다. 이제는 이전 버전의 ELB 대신 ALB 및 NLB를 사용하는 것이 권장됩니다.