IPSec(Internet Protocol Security)은 인터넷 프로토콜(IP)에서 데이터를 보호하기 위한 보안 프레임워크입니다. Layer 3에서 암호화를 제공하며, 인증을 통해 데이터의 기밀성, 무결성, 그리고 송신자의 신원을 보장합니다.
전송 모드: IP 패킷의 페이로드(데이터)만 암호화.
터널 모드: 전체 IP 패킷을 암호화하여 보안 터널을 형성.
터널모드
터널 모드에서는 전체 IP 패킷이 암호화되어 원래의 IP 헤더도 숨겨지기 때문에, 암호화된 패킷이 네트워크를 통해 전달되기 위해 새로운 외부 IP 헤더가 추가됩니다. 이 새로운 헤더는 목적지에 도달할 때까지의 경로를 결정하는 데 사용됩니다. 네트워크 라우터들은 이 외부 IP 헤더만 보고 패킷을 라우팅합니다. 목적지에 도착하면, VPN 게이트웨이가 패킷을 복호화하고 원래의 IP 헤더와 데이터를 확인해 최종 목적지로 전달합니다.
터널 모드에서는 원본 패킷(원래의 목적지 IP 주소가 포함된 패킷)이 암호화되며, 그 위에 새로운 외부 IP 헤더가 추가됩니다. 이 새로운 헤더의 목적지는 원래 패킷의 목적지가 아닌, VPN 게이트웨이나 보안 장비입니다.
과정 요약:
암호화: 원본 패킷(헤더와 데이터) 전체가 암호화됨.
외부 헤더 추가: 새로운 IP 헤더를 추가하여 네트워크에서 라우팅 가능하게 만듦.
라우팅: 라우터는 새 헤더를 기반으로 패킷을 목적지로 보냄.
복호화: VPN 게이트웨이에서 복호화 후 원래 목적지로 전달.
이 과정을 통해 암호화된 패킷이 네트워크를 통해 안전하게 목적지까지 도달할 수 있습니다.
IPSec 과정
1. IKE (Internet Key Exchange): 두 장치 간 인증 및 암호화 키 교환을 수행. 2. SA (Security Association): 암호화 및 인증에 대한 보안 매개변수를 설정. 3. SAD (Security Association Database): 설정된 SA가 저장되고, IPSec 통신에 적용될 때 사용됨. 4. ESP(Encapsulating Security Payload) 또는 AH(Authentication Header): 암호화 및 인증을 적용해 트래픽을 보호. 5. 암호화된 패킷이 안전하게 전송되고 복호화됨.
1. IKE (Internet Key Exchange)
두 노드간의 인증은 공개 키 암호화 방식(예: 인증서) 또는 사전 공유 키(PSK)를 사용한다.
Phase 1 (보안 채널 설정):
목적: 인증과 키 교환을 통해 안전한 보안 채널 생성.
결과: IKE SA 설정, 이후 IKE 메시지는 보안 채널을 통해 보호됨.
Phase 2 (IPSec SA 협상):
목적: 실제 데이터 트래픽을 보호할 SA 설정.
결과: IPSec SA가 설정되고, IPSec 트래픽이 이 SA를 통해 암호화 및 인증됨.
2. SA (Security Association) 두 장치 간 보안 매개변수(암호화 알고리즘, 인증 방법, 키 등)에 대한 합의를 의미합니다.
Blocking / Non Blocking Synchronous / Asynchronous
Blocking / Non Blocking
Blocking / Non Blocking은 호출되는 함수가 바로 제어권을 리턴 하느냐 마느냐 가 관심사
제어권을 리턴하지 않으면 Blocking
제어권을 리턴하면 NonBlocking
→ 제어권이 누구한테 있는지?
Synchronous / Asynchronous
Synchronous / Asynchronous는 호출되는 함수의 작업 완료 여부를 누가 신경 쓰냐 가 관심사
호출되는 함수의 작업 완료를 호출한 함수가 확인하면 Synchronous (동기)
호출되는 함수의 작업 완료를 호출된 함수가 확인하면 Asynchronous (비동기)
→ 호출한 함수의 완료 여부를 누가 확인하는지?
비동기 방식은 멀티 스레드 , 단일 스레드?요점은 비동기 방식은 스레드를 효율적으로 운용하여 반응성을 향상시키는 것비동기 방식 DB I/O가 발생하면 DB I/O는 다른 스레드에게 넘기고, 나머지 작업을 수행
기존 방식 DB I/O가 발생하면 다른 작업을 수행하지 않고, DB데이터가 올 때까지 기다림.
단일 스레드에서도 가능하다고는 하는데, 사실은 다른 프로세스의 스레드를 사용한다. 다른 스레드 또는 다른 프로세스의 스레드를 사용하므로 결국, 멀티 스레드가 맞다.
동기?
**작업의 완료 확인 방식에서의 동기(synchronous):**
작업을 호출한 쪽이 결과가 반환될 때까지 기다린다는 의미입니다.
비동기(asynchronous)는 작업의 완료를 기다리지 않고 다른 작업을 수행하며,
작업의 결과는 나중에 돌려받습니다.(콜백, 이벤트, 프로미스 등을 통해).
**쓰레딩과 Race Condition 문맥에서의 동기(synchronization)**:
쓰레드 간의 실행 순서나 자원 접근을 조절하는 방식을 의미합니다.
즉, 어떤 일련의 작업이 '동기화' 되어 있다면, 그 작업들은 미리 정의된 어떠한
순서에 따라 실행되어야 하며, 이를 통해 레이스 컨디션을 방지할 수 있습니다.
**Synchronous (동기):** 시간에 대한 것
동기 방식은 하나의 작업이 완료되어야 다음 작업이 시작됩니다.
여기서는 `시간의 흐름`에 집중이 되어 있습니다.
**-> 시간**
**Synchronization (동기화):** 상태나 데이터의 일관성
여러 프로세스나 쓰레드가 동시에 어떠한 자원을 접근할 때 그 순서와 방식을
조절하여 `데이터의 일관성`을 유지하는 것을 의미합니다.
**-> 상태**
→ 동기가 헷갈리는 이유
결론
Blocking + Synchronous: 요청을 보내고 응답을 받을 때까지 아무 것도 하지 않는 상태로 대기.이렇게 되면 시스템의 효율성이 떨어짐 긴 대기 시간 동안 다른 중요한 작업을 처리할 수 없게 된다.
Non-Blocking + Asynchronous: 요청을 보내고 바로 다른 작업을 계속 진행. 응답이 오면 해당 응답을 처리하는 콜백 함수나 이벤트 리스너를 통해 처리함 이 방식은 시스템의 효율성, 반응성을 크게 향상 시킬 수 있다.
→ 결국, 작업 시간이 긴 여러 DB I/O, 네트워크 처리는 비동기 방식이 좋다는 내용 👍
예시
프론트
왜 Javascript에서 axios 호출을 비동기식이라고 하는지?
Web APIs Ajax 요청, setTimeout(), 이벤트 핸들러의 등록과 같이 웹 브라우저에서 제공하는 기능들을 말한다.
이러한 요청들의 처리가 JavaScript 엔진의 쓰레드와는 다른 쓰레드들에서 이뤄진다는 점이다.
JavaScript 엔진의 스택에서 실행된 비동기 함수가 요청하는 비동기 작업에 대한 정보와 콜백 함수를 웹 API를 통해
브라우저에게 넘기면, 브라우저는 이러한 요청들을 별도의 쓰레드에 위임 해당 요청이 완료되는 순간 콜백 함수를 JavaScript 엔진의 태스크 큐라는 곳에 집어넣는다.
→ JS가 비동기 함수를 실행하면, JS는 이 함수들에 대해 신경 쓰지 않는다. (비동기)
호출된 함수는 브라우저가 신경 쓰며, 작업을 완료하면 JS에게 Call Back 을 준다.
async function fetchExternalData() {
const response = await fetch('<http://external-service/data>');
const data = await response.json();
// 위 요청-응답을 비동기로 브라우저에게 넘겨 처리하고, 아래 작업을 바로 실행함
otherWork();
return data;
}
백엔드
**WebFlux**는 Spring 5에서 도입된 반응형 프로그래밍 모델로, Non-Blocking + Asynchronous 방식 WebFlux는 Project Reactor를 기반으로 하며, **Mono**와 **Flux**라는 반응형 스트림 타입을 제공
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
@Service
public class ExternalService {
@Autowired
private WebClient webClient;
public Mono<String> fetchExternalData() {
String data = webClient.get()
.uri("/data")
.retrieve()
.bodyToMono(String.class);
// 위 요청-응답을 비동기로 처리하고, 아래 작업을 바로 실행함
otherWork();
}
}
! 질문
비동기 방식이 무엇인가?
→ DB I/O, 네트워크 작업 등의 시간 소요가 큰 작업의 완료를 기다리지 않고, 해당 작업 완료 시 콜백을 통해 결과를 받아오면서 동시에 다른 작업을 계속 수행하는 방식을 의미합니다.
package Search.BinarySearch;
public class BinarySearchTest {
static int[] arr;
public static void main(String[] args) {
arr = new int[]{1,3,5,7,9,11,13};
int idx = BinarySearchCode(9);
System.out.println(idx);
}
public static int BinarySearchCode(int findNumber){
int s = 0;
int e = arr.length - 1;
int mid;
int returnNumber = 0;
while(s <= e){
mid = (s+e) / 2;
if(findNumber == arr[mid]) {
returnNumber = mid;
break;
}
else if(findNumber > arr[mid])
s = mid + 1;
else if(findNumber < arr[mid])
e = mid - 1;
}
return returnNumber;
}
}
이분 탐색의 코드 자체는 간단하다.
left에서 시작하는 s, right에서 시작하는 e가 서로 교차하게 되면 종료한다.
(s+e)/2를 이용한 중간 값 mid를 계속 조건에 맞게 변화시키며 탐색범위를 이분한다.
찾지 못하였다면 그냥 종료될 것이고, 찾았다면 idx를 리턴한다.
이분 탐색에서 가장 중요하다고 생각하는 점은
변하는 가변 값과 변하지 않는 기준 값이다.
기준 값과 가변 값과의 비교를 통해 s, e 범위를 결정한다.
현재 코드에서는 찾을 숫자(기준 값)를 기준으로
mid를 이용해서 가변 값과의 비교를 통해 s, e를 결정하고 있지만
Prametric Search를 하게 되면 기준 값은 문제를 보고 결정을 해주어야 한다.
public static long binarySearch(int need){
long s = 0;
long e = 2_000_000_000;
long returnHeight = 0;
while(s <= e){
long mid = (s + e) / 2;
// 기준값 설정
// 자른 값들의 총합을 이용
long sum = 0;
for(int i = 0; i<arr.length; i++){
int ele = arr[i];
if(ele > mid)
sum += ele - mid;
}
if(sum >= need) { // 조건을 만족하므로 범위를 더 엄밀하게 줄임
s = mid + 1;
returnHeight = mid; // 조건을 충족한다면 일단 저장
}else if(sum < need)
e = mid - 1;
}
return returnHeight;
}
백준 2805 나무자르기 문제의 코드 일부다.
해당 문제에서 기준 값은 need 이다. (함수의 매개변수로 받고 있음)
가변 값은 mid를 이용해 구한 sum이다.
mid를 기준으로 자른 값들의 총합(sum)이 need 이상이면,
더 엄밀하게 자르기 위해 s를 더 올려서 mid를 높인다.
만족하지 않는다면 e를 낮춰서 mid를 낮춘다.
탐색 범위를 마지막에 만족하는 것까지 좁힐 수 있으므로 최대값을 구할 수 있다.
이분 탐색, 매개 변수 탐색을 구현할 땐 기준 값, 가변 값을 무엇으로 할 지 항상 생각하자.
rank() over (order by @column [asc or desc]) // 중복, 순위 밀림 => 1, 1, 1, 4 ...
dense_rank() over (order by @column [asc or desc]) // 중복, 순위 밀리지 않음 => 1, 1, 1, 2, 2 ...
row_number() over (order by @column [asc or desc]) // 순서대로
select 절에서 만들어지기 때문에 Oracle rownum처럼 추가로 view로 만들어서 정렬할 필요가 없다.
문법
distinct
중복 행 제거 (컬럼이 아닌, 행 전체 기준)
order by
[option] asc, desc
limit
0부터 N까지 조회
특이한 점은 전체를 조회할 때 N을 큰 숫자로 지정함
ex) limit 0, 19221032181328091
like, not like
where @column like '% 문자%' // 모든 문자, % 자리에 어떠한 문자도 없어도 조회
where @column like '_문자' // 한 개, 숫자 자릿수도 가능
between
@column between 3 and 15 // 3 이상 15 이하
if(조건식, true일 경우, false일 경우)
ifnull(@column, null일 경우)
집계 group by
mysql5 -> mysql8 변경사항
select min(stock_quantity), title
from books
group by released_year;
min(stock_quantity)는 집계 함수인 반면
title은 집계 함수의 결과가 아니고, group by의 대상도 아니라서
여러 값이 존재해서 오류를 일으키거나, 임의의 값을 가져오게 된다.
select min(stock_quantity), title
from books
group by title;
title이 group by의 대상이라서, 대표 값이 명확히 있기 때문에 가능하다.
group by 이후에 min(stock_quantitiy) 행을 보고자 할 때 서브 쿼리를 활용
select *
from books
where stock_quantity
in (select min(stock_quantity)
from books
group by released_year);
group by
select집계 함수, group by 대상만 사용 가능
집계 함수
count(), min(), max(), avg(), sum()
집계함수는 중첩할 수 없다. max(count(@Column)) 불가능
null 값을 집계 함수에 포함시키려면 IFNULL, CASE를 사용하면 된다.
EX) SUM(IFNULL(<COLUMN>, 1)
분기문
if (조건식) then
명령문
elseif (조건식) then
명령문
else
명령문
end if
case
when (조건식) then 명령문
when (조건식) then 명령문
when (조건식) then 명령문
else
end case
while(조건식) do
명령문
end while
조인
join(기본 조인), inner join(내부 조인), equi join(동등 조인)은 전부 다 같다.
natural join - join을 수행한다. (단, 조인에 사용한 열은 한 번만 추출)
마찬가지로
left outer join과 left join의 차이는 없다.
명시하는 방법 때문에 종류가 많아 보이지만 사실 같은 것이 많다. 헷갈리지 말자.
조인 종류
inner join
left join
right join
full outer join [mysql 에선 지원하지 않는다.]
self join
cross join
@sql
SELECT g1.pg, g1.af, b.title FROM (select max(pages) as pg, author_fname as af from books group by author_fname) g1 JOIN books b ON g1.pg = b.pages AND g1.af = b.author_fname;
from 부속 질의로 필요한 테이블을 만들고 조인하면 유용하다.
join 조건에 and를 사용하여 더 분명하게 join 해줄 수 있다.
ON table.col BETWEEN 10 AND 20
join 조건에 between으로 범위 조인도 가능하다.
UNION
관계없는 테이블을 합칠 수 있음
필드명(as 가능)과 데이터 타입이 같아야 함
중복 값은 기본적으로 제거되지만 필요한 경우 UNION ALL
@sql
(select city, char_length(city) from station order by char_length(city) asc, city asc limit 1) union (select city, char_length(city) from station order by char_length(city) desc, city asc limit 1);
부속 질의
select
scalar 부속 질의 (단일행, 단일열)
from
inline-view (가상의 테이블을 일시적 생성)
where
중첩 부속 질의
단일 행 단일 열 - 비교 연산자
다중 행 단일 열 - all, any
다중 행 다중 열 - in, exists
단일 행 단일 열
비교 연산자, select에서도 사용 가능한 scalar 부속 질의
다중 행 단일 열 ALL, ANY
any는 부속 질의의 결과가 하나라도 만족하면 true가 된다.
단일 열 이어야 한다.
다중 행 다중 열 IN, EXISTS
select * from students s join papers p on s.id = p.student_id where (p.grade, p.student_id) in ( (60, 1), (75, 1) ); # 괄호 필수
SQL 프로그래밍
delimiter를 변경해주는 이유는 선언 시에 세미콜론이 문장의 끝이 아님을 알려줘야 하므로 변경을 해준다.
변수 선언과 대입
set @변수명 = 대입값;
프로시저
프로시저를 create할 때는 종료 문자 delimiter변경해주어야 한다.
프로시저 안에서 사용되는 변수 선언 declare 변수명 타입 [default n]
변수의 값 변경은 set
drop procedure if exists testProcedure; delimiter $$ create procedure testProcedure( in num1 int, // input in num2 int, out num3 int, // output out num4 int
) begin
declare num5 int default 5; // 변수 선언
set @num10 = 10; // 변수 선언 대입
set num3 = num1 + num2; // 값 변경 set num4 = num1 - num2; end $$ delimiter ;
set @add = 0; set @sub = 0;
call testProcedure(5, 10, @add, @sub);
함수
프로시저와의 차이점은 파라미터 in, out 이 없다. 입력만 가능하다.
return 에 반환 데이터 형식을 지정해야 한다.
함수 호출은 select 문장 안에서 호출한다.
함수 내부에서 select 사용이 불가능하다.
커서
# 프로시저 내부
declare EOR boolean default false; // 행의 끝을 알릴 변수
declare 커서명 cursor for (select sql) // 커서 선언
declare CONTINUE HANDLER for not found set EOR = true; // 더 읽을 행이 없을 때 동작할 명령어
open 커서명
cursor_loop : loop
fetch 커서명 into 저장할 변수 // 커서 선언 -> 결과 sql 칼럼 개수에 맞게 변수 설정
if EOR then leave cursor_loop // 더 읽을 행이 없으면 true
end if
set sum = sum + 결과 변수
end loop cursor_loop
close 커서명
mysql, rownum 만들기 select @rownum:= @rownum +1 as rownum, t.* from table1 t, (select @rownum := 0) r;