p,m = map(int, input().split())
res=[]
for i in range(p):
l,n =input().split()
l = int(l)
if(len(res)==0):
res.append([(l,n)])
continue
flag=True
for j in range(len(res)):
if len(res[j])==m:
continue
if abs(res[j][0][0]-l)<=10:
res[j].append((l,n))
flag = False
break
if flag:
res.append([(l,n)])
for i in res:
i.sort(key=lambda x: x[1])
if(len(i)==m):
print('Started!')
else:
print('Waiting!')
for l,n in i:
print(l,n)
def solution(dirs):
answer = 0
num = {'U':(0,1),'D':(0,-1),'R':(1,0),'L':(-1,0)}
res={}
visited = set()
x, y = 0, 0
for i in dirs:
nx, ny = x + num[i][0], y + num[i][1]
if -5 <= nx <= 5 and -5 <= ny <= 5:
if ((x, y), (nx, ny)) not in visited:
answer += 1
visited.add(((x, y), (nx, ny)))
visited.add(((nx, ny), (x, y)))
x, y = nx, ny
return answer
풀이
중복을 제외하고 방문한 선분을 체크하기
입력받는 문자열에 따라 이동하는 좌표값 딕셔너리를 구현.
입력에 따라서 x,y를 움직인다. -5 ~ 5의 범위는 넘어가면 continue 해준다,
set()에 이동좌표를 넣어서 만약 그 좌표가 존재하지 않으면 answer+=1해주고, 존재하면 중복한 값이라고 판단하고 넘어간다.
def changeStrToInt(time):
return int(time[0:2]) * 60 + int(time[3:])
def solution(book_time):
sort_time = sorted([[changeStrToInt(i[0]), changeStrToInt(i[1]) + 10] for i in book_time])
res = []
for i in sort_time:
if len(res)==0:
res.append(i)
continue
for j in range(len(res)):
if(i[0] >= res[j][1]):
res[j] = res[j]+i
break
else:
res.append(i)
return len(res)
풀이
빈틈없이 예약해서 최소의 방 개수를 구하자
문자열로 입력받은 시간을 분으로 그리고 int형으로 만들어주는 함수를 작성한다.
그 다음 변환한 시간을 바탕으로 정렬해준다
정렬한 시간을 바탕으로 res배열에 넣어준
res배열이 비어 있으면 바로 넣어준다.
res배열을 돌면서 각각의 res배열의 제일 마지막 시간이 현재 첫번째 시간보다 작으면 거기 넣어준다.
http의 보안버전은 효율적이고 이식성이 좋고, 관리가 쉬워야 하며, 현실 세계의 변화에 대한 적응력이 좋아야한다. 또한 사회와 정부의 요구사항에도 맞아야한다.
다음을 제공해주는 HTTP의 보안기술이 필요하다.
서버 인증 : 클라이언트는 자신이 위조된 서버가 아닌 진짜와 이야기하고 있음을 알 수 있어야함
클라이언트 인증 : 서버는 자신이 가짜가 아닌 진짜 사용자와 이야기하고 있음을 알 수 있어야 한다.
무결성 : 클라이언트와 서버는 데이터가 위조되는것을 방지해야한다.
암호화 : 클라이언트와 서버가 서로 안전하게 대화해야 한다.
효율 : 저렴한 클라이언트나 서버도 이용할 수 있도록 알고리즘은 충분히 빨라야 한다.
편재성(Ubiquity) : 프로토콜은 거의 모든 클라이언트와 서버에서 지원되어야 한다.
관리상 확장성 : 누구든 어디서든 즉각적인 보안 통신을 할 수 있어야 한다.
적응성 : 현재 알려진 최선의 보안 방법을 지원해야 한다.
사회적 생존성 : 사회의 문화적, 정치적 요구를 만족시켜야 한다.
HTTPS
http를 안전하게 만드는 방식 중에서 가장 인기 있는 것
보안 전송 계층을 통해 전송되는 http이다
모든 주류 브라우저와 서버에서 지원한다.
firefox, safari, chore, edge 등등
모든 http 요청과 응답 데이터는 네트워크로 보내지기 전에 암호화된다. https는 http의 하부에 “전송 레벨 암호 보안 계층”을 제공함으로써 동작. → 이 보안 계층은 안전 소켓 계층(SSL, Secure Sockets Layer)혹은 그를 계승한 전송 계층 보안(TLS, Transport Layer Security)을 이용하여 구현. → SSL과 TLS는 사실상 같기 때문에 SSL이라고 표기하기도 함
SSL : Netscape사에서 1995년에 만든 통신 프로토콜
TSL : SSL의 3.0버전을 가지고 Netscape가 개발에서 빠지며 국제 인터넷 표준화 기구 **IETF(Internet Engineering Task Force)**에서 만든 프로토콜 ⇒ 현재는 SSL 2.0 및 3.0이 전부 사용 중지, 사실상 TLS만 사용. ⇒ 또한 TLS 1.0과 1.1도 사용 중지 예정
![[123.png]] ![[765432.png]]
→ 대부분의 경우, tcp 입력/출력 호출을 ssl 호출로 대체하고, 몇가지의 설정만 바꿔주면 된다.
인코딩 및 디코딩 작업은 대부분 SSL 라이브러리 안에서 일어나기 때문에 http의 로직을 크게 변경할 필요가 없다. → 대부분의 경우, tcp 입력/출력 호출을 ssl 호출로 대체하고, 몇가지의 설정만 바꿔주면 된다.
암호(cipher)
암호 : 메시지를 인코딩하는 어떤 특정한 방법과 나중에 그 비밀 메세지를 디코딩하는 방법을 말함.
원본 메세지(텍스트 or 평문)에 암호를 적용하면 암호문이 된다.
역사상 최초의 암호 : 스키테일 암호
카이사르의 순환암호
메세지의 각 글자를 알파벳 순서상 세번 뒤의 글자로 바꾸는 방법 사용
디지털 암호
디지털 시대로 넘어오면서 두가지의 변화
속도 및 기능에 대한 전폭적인 성장, 훨씬 더 복잡한 인코딩과 디코딩이 가능해짐
매우 큰 키를 지원하는 것이 가능해져 단일 암호 알고리즘으로 키의 값마다 다른 수조개의 암호 알고리즘을 만들어 낼 수 있게 됨.
평문 메세지 P, 인코딩 함수 E, 디지털 인코딩 키 e가 주어졌을 때 암호문 C를 생성할 수 있다. ![[62138761283.png]]
자세한 암호화에 관한 내용은 전 게시글에 존재한다
사이트 인증서 검사
날짜 검사
인증서의 유효기간을 검사
서명자 신뢰도 검사
발급받은 CA가 믿을만한 기관인지 검사
서명 검사
CA의 공개키를 사용해 인증서의 무결성 검증
사이트 신원 검사
인증서의 도메인 이름과 서버의 도메인 이름이 맞는지 검사
와이어 샤크로 ssl handshaking 뜯어보기
와이어 샤크를 사용해서 naver에 접속할 때 ssl 인증이 어떻게 이루어지는지 확인하기
naver의 ip주소를 알아내기 위해서 nslookup 명령어 사용
와이어샤크에서 ipv6를 사용하길래 네이버의 ipv6 주소를 알아냄
와이어 샤크에서 naver의 ssl handshake만 보기 위해서 설정
설정 후 네이버 창을 켠뒤 와이어샤크 측정 종료
client hello
클라이언트가 서버에 처음으로 연결을 요청할 때 보냄
client의 SSL 버전, 세션 ID, Cipher Suites 등을 보낸다.
2. server hello
클라이언트의 응답을 받았으며 SSL/TLS Handshake 를 진행
클라이언트에서 받은 Cipher Suites 목록 중에 사용할 버전 확정해서 응답
3. Certificate
서버가 클라이언트에게 자신의 디지털 인증서를 제공
이 메세지에 있는 디지털 인증서를 기반으로 클라이언트가 서버의 신뢰성을 확인.
4. Server Key Exchange
서버 측에서 키 교환을 위해 서버의 인증서를 넘어서는 추가 데이터가 필요할 때 요청하는 메세지 Server Hello Doine
ssl handshake에서 서버의 역할이 완료되었음을 알림 (서버가 보낼 건 다보냈다)
5. Client key Exchange
클라이언트에서 공유할 비밀키 생성 change Cipher Spec
이제부터는 아까 위에서 협상했던 암호화 방법으로 통신을 전환하자고 알리는 것
6. New Session Ticket
일종의 캐시 역할.
클라이언트가 나중에 연결 시 빠른 연결을 위해 세션 티켓을 저장 change Cipher Spec
서비스 및 서비스 시스템의 성능을 확인하기 위해 실사용 환경과 비슷한 환경에서 테스트를 진행하는 것
어느 정도의 부하를 견딜 수 있는지
한계치에서 병목이 생기는 지점 찾기
자원을 효율적으로 사용할 수 있다.
메모리 누수, 오류, 오버플로우 발생하는지 확인 가능
최악의 상황에서 어떤 동작을 하는지 확인 가능
장애 조치와 복구의 동작을 확인 가능
구글 리서치 자료에 따르면 3초 이상 걸리면 53%의 사용자가 떠나며, 표시 속도가 1초에서 7초로 늘어난다면 이탈률은 113%가 된다고 함
→ 웹 성능테스트를 통해 사용자에게 빠른 서비스를 제공할 수 있어야 한다.
성능 테스트의 기대 효과
시스템 측면 : 주요 성능 결함 및 구조적 위험 우선 식별, 운영시스템 성능 최적화, 유지보수 비용 및 시 스템 비용 최소화 등
사용자 측면 : 서비스의 품질 개선, 응답시간 향상을 통한 업무 효율 증대, 사용자 만족도 향상 등
nGrinder
nGrinder는 네이버에서 성능 측정 목적으로 jython(JVM위에서 파이썬이 동작)으로 개발 된 오픈소 스 프로젝트이며,2011년에 공개 됨.
실제 서비스에 투입 되기 전, 실제와 같은 환경을 만들어 놓고 서버가 사용자를 얼마 만큼 수용할 수 있는지를 실험 할 때 사용
언어로는 jython (java + python)과 Groovy(자바 호환)를 지원.
Controller
퍼포먼스 테스팅(부하테스트)를 위해 웹 인터페이스를 제공
테스트 프로세스를 체계화
테스트 결과를 수집해 통계로 보여줌
Agent
Controller의 명령을 받아 실행.
target이 된 머신에 프로세스와 스레드를 실행시켜 부하를 발생.
대상 시스템의 CPU와 Memory를 모니터링.
Target
부하 테스트를 받는 머신
설치 방법
controller와 agent를 둘다 설치해야 한다.
docker를 사용하는 방법
운영 체제별 도커 데스크탑 설치
우분투 도커 설치
controller 설치 및 실행
# docker hub에서 이미지 가져오기
docker pull ngrinder/controller
# 가져온 이미지로 실행하기
docker run -d -v ~/ngrinder-controller:/opt/ngrinder-controller --name controller -p 80:80 -p 16001:16001 -p 12000-12009:12000-12009 ngrinder/controller
agent 설치 및 실행
# docker hub에서 이미지 가져오기
docker pull ngrinder/agent
# 가져온 이미지로 실행하기
# 위에서 생성했던 controller와 연결
docker run -d --name agent1 --link controller:controller ngrinder/agent
직접 파일을 다운로드해서 실행시키는 방법
이 경우에 자바를 사용해야한다.
자바 다운로드
nGrinder 다운로드
받고싶은 버전(보통은 최신버전)을 선택하여 .war 파일을 다운 받는다.
다음 받은 후 해당 명령어를 실행한다.
# java -Djava.io.tmpdir=[임시파일을 저장할 경로] -jar [다운받은 war 파일 이름] --port=[열고싶은 포트번호]
# 예시
java -Djava.io.tmpdir=/Users/choi/Desktop/test/ -jar ngrinder-controller-3.5.8.war --port=8301
정상적으로 실행 되었다면 localhost:[지정한 포트]로 접속할 시 nGrinder 메인 화면이 뜬다
초기 관리자 ID와 password는 둘다 admin이다.
접속 후 오른쪽 상단의 admin 클릭 후 에이전트 다운로드 클릭 해서 압축 파일 다운로드
다운받은 압축 파일을 압축해제 해제
# tar -xvf [다운받은 압축파일]
tar -xvf ngrinder-agent-3.5.8-localhost.tar
압축 해제 후 run_agent.sh 실행 (윈도우는 .bat)
./run_agent.sh
이렇게 실행할 경우 agent도 틀어짐
사용 방법
에이전트
테스트에 사용할 에이전트의 개수
스크립트
사용자가 해당 주소로 부하를 걸 스크립트를 보여줌
RHEAD
선택된 스크립트의 내용을 보여주는 페이지로 이동
테스트 대상 서버
테스트를 진행할 서버의 리스트를 보여주며, 추가버튼 클릭 시 테스트 받을 서버를 늘릴 수 있다.
테스트 기간
해당 테스트를 얼마만큼 실행할 지 설정하는 항목
실행 횟수
사용자가 설정한 쓰레드당 몇 번의 테스트를 실행할 것인지를 지정
Ramp-Up
점차 부하를 가할 수 있는 기능. 부하를 가할 때, 가상 사용자 수를 늘리는 것 이 아닌 process나 thread를 늘린다
초기 개수
처음 시작 시 가상사용자의 수를 설정
초기 대기 시간
테스트를 언제부터 실행시킬 지 설정
증가 단위
해당 process/thread를 몇 개씩 증가시킬지를 설정
Ramp_Up 주기
상승 시간을 설정
여러가지 스크립트를 작성해서 각 기능에 대해 얼마나 부하가 걸리는지 확인할 수 있다.
// 로그인 페이지 예시 스크립트
@Test
public void testLogin() {
// 메인 페이지 요청
HTTPResponse mainPageResponse = request.GET("http://example.com/main")
// 로그인 요청
Map<String, Object> loginParams = [username: "user", password: "pass"]
HTTPResponse loginResponse = request.POST("http://example.com/login", loginParams)
// 로그인 응답 확인
assertThat(loginResponse.statusCode, is(200))
}
도커 이미지를 저장하고 가져다 쓰기 위한 Object Storage와 Container Registry를 생성해준다.
Object Storage 생성
Object Storage 이용 신청
이용 신청 후 버킷 생성
이름 입력 후 설정 건드리지않고 “다음” 버튼 클릭 후 버킷 생성
Container Registry 생성
Container Registry로 이동 후 “레지스트리 생성” 클릭
이름 입력 및 생성한 Object Storage 넣은 후 생성
vite+react+typescript에서 Dockerfile 만들기
배포할 프로젝트 최상단에 nginx를 사용하여 배포하는 Dockerfile을 생성
(참고로 현재 배포에 사용하는 gihub repo가 client와 server둘다 있어서 프론트 코드는 /client에 들어가 있다.)
# 첫 번째 단계: 빌드 환경 구축
FROM node:lts-alpine as build-stage
WORKDIR /app
# 의존성 파일 복사 및 설치
# COPY [내 package.json 파일과 yarn.lock 파일의 경로] [복사할 위치]
COPY ./client/package.json ./client/yarn.lock ./
RUN yarn install && yarn global add typescript
# 소스 코드 복사
COPY ./client .
RUN ls -l
# 애플리케이션 빌드
RUN yarn build
# 두 번째 단계: Nginx를 사용하여 애플리케이션 서빙
FROM nginx:stable-alpine as production-stage
# 빌드된 파일을 Nginx 서버로 복사
COPY --from=build-stage /app/dist /usr/share/nginx/html
# 80 포트 노출
EXPOSE 80
# Nginx 실행
CMD ["nginx", "-g", "daemon off;"]
CLI로 container registry에 도커 이미지 build,push 하기
NCP container registry에 로그인하기 위해서는 마이페이지에서 인증키 생성이 필요하다.
마이페이지 - 계정관리 - 인증키관리 - 신규 API 인증키 생성 - Access Key ID, Secret Key가 각각 ID, PW로 로그인시 사용된다.
해당 repository에 접근하기 위해서는 로그인이 필요하다.
Registry URL은 Container Registry에서 생성한 레지스트리를 클릭하면 Public Endpoint가 있는데 그것을 사용해주면 된다.
docker login <CONTAINER_REGISTRY_URL>
다음을 입력하면 username과 password를 입력하라고 나오는데, 위에서 발급한 Access Key ID를 username으로, secret key를 password로 입력하면 된다.
도커 파일을 작성한 배포할 프로젝트의 최상단에서 다음 명령어를 쳐주면 build되고 push되어서 Container Regisrty에 반영된다.
ssh-keygen -t rsa -b 4069 -C {자신의 메일} -f "./my_key" -N ""
# rsa 방식으로 4096비트를 사용해서 생성한다.
생성 완료되면
Generating public/private rsa key pair.
Your identification has been saved in ./my_key
Your public key has been saved in ./my_key.pub
The key fingerprint is:
SHA256:[여러 문자] [입력한 메일 주소]
The key's randomart image is:
+---[RSA 4069]----+
|+O |
|++@+. . . |
|oo.+ + o + |
|=. o o + |
|E.. . .So |
|o* . .. |
|..* ..+. |
|.. o. o |
| .o . |
+----[SHA256]-----+
이런 메세지가 뜨면서 파일 두개가 생성된다. my_key와 my_key.pub이 생성되는데 .pub가 공개키, my_key 암호키 즉 쌍(pair)으로 생성된다.
생성한 키페어를 테라폼 파일에 등록한다.
# ec2.tf
resource "aws_key_pair" "ec2_key" {
key_name = "my_key"
public_key = "my_key.pub 안에 있는 내용 전부 붙여넣기" or file("./my_key.pub")
}
ec2.tf를 만들어 주고 위의 코드를 작성해서 생성한 키페어를 테라폼에서 사용할 수 있게 만들어준다.
ec2 생성
aws_instance를 사용해서 쉽게 생성할 수 있다.
#ec2.tf
resource "aws_instance" "real_ec2" {
ami = "ami-0ba5cd124d7a79612"
#ubuntu 20.04의 ami
instance_type = "t3.small"
security_groups = [aws_security_group.realPublicSG.id]
subnet_id = aws_subnet.realPublicSubnet.id
key_name = aws_key_pair.ec2_key.key_name
root_block_device { #볼륨 설정 가능
volume_size = 200
volume_type = "gp3"
}
tags ={ #이름 설정 가능
Name = "real_ec2"
}
}
인스턴스 타입을 설정할 수 있다.
ami의 경우 콘솔에서 ami검색을 통해 id를 확인할 수 있다.
작성완료 했으면 terraform plan 후 apply (apply는 실제 환경에 적용이기 때문에 자주하지 않더라고 plan은 자주해서 오류를 바로바로 잡아내자!)