AWS 강의 시작

AWS DVA-C02 시험 공부 정리

시작부터 시험에 맞춰진 강의라는 느낌을 받았다.

섹션 1 ~ 11 까지 기초 강의로 되어 있고, 3, 4 & 5는 스킵해도 된다고 되어 있어서 당황스럽긴 한데..

한번보고 안 볼꺼면 어떻게 보라고 강의 순서까지 정리해두네 😃

Please watch the following lectures:

  • Section 7 - AWS Fundamentals: ELB + ASG
    • Auto Scaling Groups - Instance Refresh
  • Section 8 - AWS Fundamentals: RDS + Aurora + ElastiCache
    • ElastiCache Strategies
    • Amazon MemoryDB for Redis
  • Section 9 - Route 53
    • Routing Policy - Traffic Flow & Geoproximity Hands On
  • Section 10 - VPC Fundamentals
    • VPC Fundamentals - Section Introduction
    • VPC, Subnets, IGW and NAT
    • NACL, SG, VPC Flow Logs
    • VPC Peering, Endpoints, VPN, DX
    • VPC Cheat Sheet & Closing Comments
    • Three Tier Architecture
  • Section 12 - AWS CLI, SDK, IAM Roles & Policies
    • AWS EC2 Instance Metadata
    • AWS EC2 Instance Metadata - Hands On
    • AWS CLI Profiles
    • AWS CLI with MFA
    • AWS SDK Overview
    • Exponential Backoff & Service Limit Increase
    • AWS Credentials Provider & Chain
    • AWS Signature v4 Signing
  • Section 15 - CloudFront
    • CloudFront - Caching & Caching Policies
    • CloudFront - Cache Behaviors
    • CloudFront - Caching & Caching Invalidations - Hands On
    • CloudFront - Signed URL / Cookies
    • CloudFront - Signed URL - Key Groups + Hands On
    • CloudFront - Advanced Concepts
    • CloudFront - Real Time Logs
  • Section 16 - ECS, ECR & Fargate - Docker in AWS
    • Amazon ECS - Rolling Updates
    • Amazon ECS Task Definitions - Deep Dive
    • Amazon ECS Task Definitions - Hands On
    • Amazon ECS - Task Placements
    • Amazon ECR - Hands On
  • And everything from Section 17 onwards

이것만 들어도 되는건지는 모르겠다.


AWS 가입

이전에 aws 찍먹해보겠다고 가입했었는데, 90일 지나서 비활성화가 되어 버렸네;;

찾아보니 account+tag@mail.com 이런식으로 태그를 달면 원래 이메일 계정으로 인식해서 코드를 보내주길래 다시 가입을 했다.

시작부터 당황스러웠지만 어쩔 수 없지.

관련해서 강의에서도 정리를 해뒀는데 이건 못봤네 😂

아무튼 생성 완!!


AWS 역사와 Regions

이건 빠르게 보고 지나가자


AWS Console

Aws Console에 대한 내용을 다루는데 하나씩 보면서 친숙해지는 방법이 좋을것 같다.

이전에도 EC2와 같은 서비스를 이용해본적 있는데, 꽤 많이 한글 최적화도 된거 같고 콘솔이 친숙화가 진행된거 같다.


IAM

IAM 이란?
IAM = Identity and Access Management, Global service
로 ID와 엑세스 관리의 약자이다.

IAM에서는 사용자를 생성하고 그룹에 할당할 수 있다.

유저(Users)는 조직에서의 사람을 뜻하며 그룹으로 될 수 있다.

그룹(Groups)는 오직 유저를 포함하고 있고 다른 그룹은 포함할 수 없다.(중요)

어떤 유저는 그룹에 속해있지 않아도 된다.

또한, 각 그룹 사이에 그룹을 생성할 수 있다.

왜 사용자와 그룹을 생성할까?

AWS를 사용하기 위한 Permissions 때문이다.

유저와 그룹은 정책이라고 불리는 JSON 문서를 기반으로 한다.

이러한 정책은 유저들의 사용 권한을 결정한다.
AWS에서는 최소한의 원칙을 적용할 수 있다. 유저가 필요한것 보다 더 많은 권한을 주지 않는다.

Tags

Tags는 AWS 어디에서나 사용 가능한 선택 사항이다. 메타데이터를 여러 리소스에 남길 수 있다는 장점이 있다.

AWS Account

AWS Account 에는 사용자 계정이 들어 있고, 로그인 url가 있다.
해당 url는 alias(별칭)을 생성해서 간단하게 접근 가능하다. (단, unique 해야 한다.)

IAM 유저 로그인

해당 로그인 url를 통해서 관련 계정으로 들어갈 수 있고, IAM 유저 로그인 상에 alias를 통해서 접근이 가능해진다.
항상 콘솔 로그인에서 루트계정과 IAM계정의 접근이 이해가 안갔었는데, 이 부분을 확실하게 이해할 수 있었던것 같다.

IAM Policies

그룹에 IAM Policies를 적용하게 되면 그 그룹 안에 있는 모든 유저에게 접근되고 상속되게 된다.

inline policy 라는 방식으로 한 유저에게만 직접적으로 생성 가능하다.

IAM Structure

  • Version : 정책 언어 버전, 일반적으로 날짜로 되어 있는 경우가 많다.
  • ID : 정책을 확인하는 방법인데 선택사항이다.
  • Statement : 하나 이상의 구문을 작성해야 한다.
    • Sid : 구문의 식별자로 선택사항이다.
    • Effect : 해당 구문을 허용할지 거부할지에 대한 내용이다. (Allow/Deny)
    • Principal : 어떤 계정, 사용자, 혹은 역할이 이 정책에 적용될지를 결정한다.
    • Action : API 호출 목록이다.
    • Resource : 작업을 적용할 리소스 목록이다.
    • Condition : 이 정책을 적용하기 위한 조건, 선택 사항이다.
      {
      "Version": "2012-10-17",
      "ID": "S3-Account-Permissions",
      "Statement": [
       {
       "Sid": "1",
       "Effect": "Allow",
       "Principal": {
         "AWS": ["arn:aws:iam::123456789012:root"]
       },
       "Action": [
         "s3:GetObject",
         "s3:PutObject"
       ],
       "Resource": ["arn:aws:s3:::mybucket/*"]
       },
       {
       "Effect": "Allow",
       "Action": "ec2:Describe*",
       "Resource": "*"
       },
       {
       "Effect": "Allow",
       "Action": "elasticloadbalancing:Describe*",
       "Resource": "*"
       },
       {
       "Effect": "Allow",
       "Action": [
         "cloudwatch:ListMetrics",
         "cloudwatch:GetMetricStatistics",
         "cloudwatch:Describe*"
       ],
       "Resource": "*"
       }
      ]
      }
      

IAM - Password Policy

AWS에는 패스워드 정책이 다양하다.

  • 최소한의 길이 설정
  • 특별한 문자 요구
  • 스스로 패스워드 변경 허용
  • password expiration 설정하여 90일 후에 변경을 요구
  • 재사용 방지

MFA

MFA - Multi Factor Authentication
Root 계정과 IAM 유저를 보호하기 위해 사용한다.

MFA = password you know + security device you own

MFA devices options in AWS

  • Virtual MFA device
    • Google Authenticator
    • Authy
  • Universal 2nd Factor (U2F) Security Key
    • 3rd party
  • Hardware Key Fob MFA Device
  • Hardware Key Fob MFA Device for AWS GovCloud (US)

AWS Certified Developer - Associate 시험 응시

AWS DVA-C02 시험 공부 정리

회사에서 AWS를 사용하게 되면서 AWS-SDK for cpp를 다루게 되었고, 자연스럽게 AWS에 대한 관심이 생겼다.

때문에 올해가 가기 전에 AWS 자격증 공부를 한번 해보고 싶다는 생각을 했었다.

그런데 같은 생각을 가진 동료들이 있었고, 이번 기회에 같이 응시를 해보려고 한다.

때문에 이 글은 그런 공부와 관련된 내용을 기록하는 것이다.

시험 응시일은 24년 06월 21일 (금)! 화이팅해보자!!


Udemy 강의 수료 목표!

Stephane Maarek | Ultimate AWS Certified Developer Associate 2024 NEW DVA-C02

공부는 기간을 1달로 Udemy 강의를 빠르게 본 뒤에 바로 덤프 문제풀이로 들어가는 것이 최초 전략이다.

강의는 가장 유명한 Stephane Maarek의 Ultimate AWS Certified Developer Associate 2024 NEW DVA-C02 로 선택하였고, 강의 길이가 460회가 넘다보니 핸즈온은 생략하고 개념 중심으로 들을 생각이다.

강의의 절반을 차지하는 기본 개념들은 단독 문제로 거의 출제되지 않는다는 말이 있기에 2부에 해당하는 Serverless 이전의 기본 개념들(EC2, S3, DB, Route53 등)은 거의 개념만 볼 계획이고, DynamoDB, Lambda, CI/CD 중심으로 공부를 진행하려고 한다.

덤프는 examtopics 를 추천하길래 그 위주로 문제를 풀어볼 생각이고, 실제로 discussion을 통해 정답에 대한 사람들의 의견도 볼 수 있어서 정확하게 파악하기 좋을 것 같다.


강의 섹션 정리

  • Section 1 : Course Introduction - AWS Certified Developer Associate
  • Section 2 : Code & Slides Download
  • Section 3 : Getting started with AWS
  • Section 4 : IAM & AWS CLI
  • Section 5 : EC2 Fundamentals
  • Section 6 : EC2 Instance Storage
  • Section 7 : AWS Fundamentals: ELB + ASG
  • Section 8 : AWS Fundamentals: RDS + Aurora + ElastiCache
  • Section 9 : Route 53
  • Section 10 : VPC Fundamentals
  • Section 11 : Amazon S3 Introduction
  • Section 12 : AWS CLI, SDK, IAM Roles & Policies
  • Section 13 : Advanced Amazon S3
  • Section 14 : Amazon S3 Security
  • Section 15 : CloudFront
  • Section 16 : ECS, ECR & Fargate - Docker in AWS
  • Section 17 : AWS Elastic Beanstalk
  • Section 18 : AWS CloudFormation
  • Section 19 : AWS Integration & Messaging: SQS, SNS & Kinesis
  • Section 20 : AWS Monitoring & Audit: CouldWatch, X-Ray and CloudTrail
  • Section 21 : AWS Serverless: Lambda
  • Section 22 : AWS Serverless: DynamoDB
  • Section 23 : AWS Serverless: API Gateway
  • Section 24 : AWS CICD: CodeCommit, CodePipeline, CodeBuild, CodeDeploy
  • Section 25 : AWS Serverless: SAM - Serverless Application Model
  • Section 26 : Could Development Kit (CDK)
  • Section 27 : Cognito: Cognito User Pools, Cognito Identity Pools & Cognito Sync
  • Section 28 : Other Serverless: Step Functions & AppSync
  • Section 29 : Advanced Identity
  • Section 30 : AWS Security & Encryption: KMS, Encryption SDK, SSM Parameter Store, IAM & STS
  • Section 31 : AWS Other Serverless
  • Section 32 : AWS Final Cleanup
  • Section 33 : Preparing for the Exam - AWS Certified Developer Associate
  • Section 34 : Congratulations - AWS Certified Developer Associate

징그럽게 많다.. 화이팅!

일상의 기록

일상 기록

오랫만에 일상의 기록
23년에는 한 번도 기록을 하지 않았더라구..
물론 23년에는 승토리와 처음으로 해외 여행도 다녀오고 연휴도 있었고 이직을 하기 때문에 회사일에 집중하기도 했다.
그래도 너무 오랜만에 MacBook Pro를 켜면서 켜져 있는 VScode 창을 보면서 끝내지 못한 포스팅도 있었고, 기록이 22년 12월을 마지막으로 멈춰 있는 상태를 발견하고나니 반성하자 나 자신..

오늘은 승토리와 함께 아침 일찍부터 낙성대역 근처 카페에 자리잡고 각자 해야 할 일을 하고서,
저녁에는 이사가야 할 집 구경도 하고 가구의 치수도 재는 등 하려고 나왔다.
물론 내 생각보다는 너무 늦게 나온편이긴 하지만 이 정도면 선방했지!

5월 19일에 이사도 가고 새로운 직장에 조금씩 익숙해지면 다시 본격적으로 꾸준히 업데이트하며 공부할 계획을 다시 세워보겠다!
서버 개설 및 유지, 관리와 같은 부분에서 많이 부족하다는 것을 느끼고 있고, 확실히 그동안 해왔던 임베디드와는 전혀 다른 성격을 지나고 있기 때문에 서버 모니터링 & VOC와 같은 내용들을 따라가는게 어렵긴 하다.
그와 관련해서 내 NAS 서버를 관리하면서 그런 부족한 부분을 채워가보면 어떨까 지금은 생각하고 있다.

우선은 이사에 집중하고 워크스페이스 관리를 좀 더 신경써서 주기적으로 내 스스로의 가치를 올릴 수 있도록 해보겠다.

그리고 요새는 부업과 관련된 내용을 나름대로 정리하고 있다.
세상에는 내가 모르던 분야에서 다양한 부업으로 제 2의 수익을 내는 방법이 많은것을 알고서 깜짝 놀랐고,
그런 방법을 습득하고 소소하게라도 제 2의 수입을 안정적으로 만들 수 있는 노력을 할 예정이다.

또한 승토리와 6월에 결혼을 준비하는 단계에 도입하기로 했다.
이것은 엄청나게 의미 있는 것이며, 인생에서 전환기가 될 수 있다고 생각한다.
지금 이사가는 집에서 같이 시작하기에는 내가 생각했던 부분보다는 소소할 수 있겠지만, 차근차근 준비해보려고 한다. 💪

TCP(Transmission Control Protocol) / IP(Internet Protocol)

TCP를 이해하고 정리하자.

TCP 프로토콜을 자주 사용하면서도 CS 지식으로 연결되는 부분이 있기 때문에 정리하고자 한다.

TCP/IP 를 사용하면서 해당 지식을 정확하게 알지 못하는 것은 어불성설이다.
따라서 상세히 알아보고 정리하고자 한다.

TCP/IP 란?

전송 제어 프로토콜의 약자로, 인터넷 프로토콜 스위프트(IP)의 핵심 프로토콜 중 하나로, IP와 함께 TCP/IP라는 명칭으로 불린다.

TCP/IP 를 사용하겠다는 것은 IP 주소 체계를 따르고 IP Routing을 이용해 목적지에 도달하며 TCP 의 특성을 활용해 송신자와 수신자의 논리적 연결을 생성하고 신뢰성을 유지할 수 있도록 하겠다는 의미이다. 즉, TCP/IP를 말한다는 것은 송신자가 수신자에게 IP 주소를 사용하여 데이터를 전달하고 그 데이터가 제대로 도달했는지, 너무 빠르진 않았는지, 받았다는 응답이 오는지에 대한 이야기를 하는 것이다.

Transport Layer(4 Layer)

송신자와 수신자의 논리적 연결을 담당하는 부분으로, 신뢰성 있는 연결을 유지할 수 있도록 도와줍니다.
즉 Endpoint(사용자) 간의 연결을 생성하고 데이터를 얼마나 보냈는지, 얼마나 받았는지, 제대로 받았는지 등을 확인합니다.
TCP와 UDP가 대표적입니다.

Network Layer(3 Layer)

IP(Internet Protocol)이 활용되는 부분으로, 한 Endpoint가 다른 Endpoint로 가고자 하는 경우 경로와 목적지를 찾아줍니다.
이를 Routing이라고 하며 대역이 다른 IP들이 목적지를 향해 제대로 찾아갈 수 있도록 돕는 역할을 합니다,

출처 : OSI 7 Layer 쉽게 이해하기
[네트워크 엔지니어 환영의 AWS 기술블로그]

인터넷에서 무언가를 다운로드할 때 중간에 끊기거나 빠지는 부분 없이 완벽하게 받을 수 있는 이유도 TCP의 이러한 특성 덕분이다.
그렇게 때문에 위에서 언급한 것처럼 HTTP, HTTPS, FTP, SMTP 등과 같이 데이터를 안정적으로 모두 보내는 것을 중요시하는 프로토콜들의 기반이 된다.
TCP를 기반으로 하는 프로토콜들은 TCP의 3-way handshake를 거친 후, 각자 프로토콜(Layer 7)에 기반한 교환 과정을 거친다는 의미이다.

SSL Handshake

위 이미지는 TCP 기반의 프로토콜인 HTTPS의 SSL handshake를 도식화한 것이다.
TCP는 4 Layer이고 HTTPS는 7 Layer 이다.

파란색 부분은 TCP의 3-way handshake이고, 노란색 부분은 HTTPS의 SSL handshake이다.
HTTPS는 TCP 기반이기 때문에 SSL handshake에 앞서 3-way handshake를 하는 것을 볼 수 있다.

TCP 개요

TCP는 OSI 7 Layer 중에 4 계층에 해당한다. IP가 그저 목적지를 제대로 찾아가는 것에 중점을 둔다면, TCP는 통신하고자 하는 양쪽 단말(Endpoint)이 통신할 준비가 되었는지, 데이터가 제대로 전송되었는지, 데이터가 가는 도중 변질되지는 않았는지, 수신자가 얼마나 받았고 빠진 부분은 없었는 등을 점검한다.
이런 정보는 TCP Header에 담겨 있으며 SYN, ACK, FIN, RST, Source Port, Destination Port, Sequence Number, Window Size, Checksum 등과 같은 신뢰성 보장과 흐름 제어, 혼잡 제어에 관여할 수 있는 요소들을 포함하고 있다.
또한 IP Header와 TCP Header를 제외한 TCP가 실을 수 있는 데이터의 크기를 세그먼트(Segment)라고 부른다.

TCP Header

`TCP Header의 구조(출처: Wikipedia)`

TCP는 IP의 정보들뿐만 아니라 Port를 이용하여 연결한다. 한 쪽 단말(Endpoint)에 도착한 데이터가 어느 입구(Port)로 들어가야 하는지 알아야 연결을 시도할 수 있기 때문이다.

Multi Process & Thread

Multi Process & Thread를 정리하고 차이를 상세히 알아보자

CS 지식에서 제일 많이 물어보는 부분이 Multi Process와 Thread가 아닐까 한다.

학부생 시절부터 정리했던 부분이지만 다시 한 번 더 정리하고 정의하고자 한다.

Process 란?

Process란 하나 혹은 그 이상의 Thread로 실행되는 컴퓨터 프로그램의 instance이다.
Process는 Program Code와 Activity를 포함한다.

  • Wikipedia

프로세스는 가상 메모리 공간, 코드, 데이터, 시스템 자원의 집합이다.

  • Microsoft

프로세스는 운영체제가 프로그램을 실행하기 위해 필요한 가장 작은 단위의 쓰레드, 메모리, 소스코드들의 집합이며 프로그램 동작 그 자체를 의미한다.
운영체제는 프로세스를 작업의 단위로 보고 자원들을 프로세스들에 적절하게 배분한다.

쉽게 말하자면 프로세스란 실행중인 프로그램이라고 볼 수도 있다.

Process의 상태 (States)

ProcessStates 출처

위 그림을 프로세스의 5 가지 상태(Five States)라고 한다.
9 가지 상태로 상세히 표현하는 방식도 있지만 이 글에서는 5 가지 상태를 다룰 것이다.

  • New : 프로세스가 생성 되었지만, 운영체제에 의해 수행 가능한 프로세스 풀로의 진입이 허용되지 않은 상태
  • Ready : 자원이 할당되면 수행할 준비가 되어 있는 상태
  • Running : 현재 수행 중인 프로세스
  • Blocked : 입출력 연산(I/O)와 같은 작업 중 완료가 될 때까지 수행될 수 없는 프로세스
  • Exit(Terminated) : 프로세스 수행이 중지되거나, 어떤 이유로 중단되었기 때문에 프로세스 풀에서 방출된 프로세스, 종료된 상태

Process 상태 변화 요인

New -> Ready(Admitted)

New 상태에서 OS의 승인을 받아서 프로세스가 생성이 되면, 해당 프로세스의 PCB가 OS커넗의 Ready Queue에 올라온다.

Ready -> Running(Scheduler dispatch)

Ready Queue에 있는 프로세스들 중에서 스케줄링 알고리즘에 의해서 선택된 프로세스가 CPU를 할당 받는다.

Running -> Blocked(Wait)

현재 CPU의 명령을 받아서 명령어를 수행중인 프로세스가 I/O와 같은 특정 작업을 해야하는 경우 CPU를 반납하고 해당 장치 큐에 들어가게 된다.

Blocked -> Ready(I/O Completion or interrupt)

작업을 위해 장치 큐에 있던 프로세스가 디스크 컨트롤러에 의해 서비스를 받아 일을 하고,
디스크 컨트롤러가 인터럽트를 발생하여 프로세스가 한 일을(로컬 버퍼에 저장된 데이터) 메모리에 올려놓고 프로세스는 다시 Ready Queue에 들어가게 된다.

Running -> Exit

프로세스 실행이 완료되어 자원을 반납한 상태

Process 메모리

운영체제는 프로세스 마다 고유의 가상 메모리 공간을 제공한다. 이러한 메모리 공간은 Data, Text, Stack/Heap Section으로 나뉜다.

ProcessMemory 출처

  • Stack :
    • 매개변수, 지역변수, return 주소 등과 같은 데이터를 저장하는 영역이다.
    • 컴파일러에 의해 Run Time 도중 크기가 결정되며, 함수가 호출&종료 되는 시점에서 생성&제거 된다.
  • Heap :
    • new, delete, malloc, free 등을 호출하여 데이터를 저장, 관리하는 영역
    • Run Time에 크기가 결정
  • Data Section :
    • 사전에 선언된 데이터가 저장되는 영역이다. (global, staic, variables, etc)
    • Compile Time에 크기가 결정된다.
    • 내부에서 DATA & BBS 영역으로 구분된다.
      • DATA : 초기화된 전역변수가 저장되는 영역이다. (Initialized data section)
      • BBS : 초기화되지 않은 전역변수가 저장되는 영역이다. (Uninitialized data section)
  • Instruction(Text Section) :
    • 컴파일된 기계어가 저장되는 영역이다.
    • Compile Time에 크기가 결정된다.

PCB(Process Controll Block)

Process 마다 현재 상태를 하나의 데이터 구조에 저장하여 관리하는데, 이를 Process Controll Block이라고 한다.
PCB는 다른 프로세스들이 쉽게 접근할 수 없고, Kernel 영역에 저장된다.

운영체제가 프로세스를 관리하기 위해 필요한 정보를 담고 있는 자료구조이며,
주요 역할은 수행 프로세스를 인터럽트한 후 나중에 그 인터럽트가 발생되지 않은 것처럼 프로세스 수행을 재개하도록 충분한 정보를 유지하는 것이다.

PCB는 프로세스 식별자, 프로세서(CPU) 상태 정보, 프로세스 제어 정보를 담고 있다.
PCB

PCB

출처

  • 포인터 : 프로세스의 현재 위치를 저장하는 포인터 정보
  • 프로세스 상태 : 프로세스의 각 상태를 저장
  • 프로세스 번호 : 모든 프로세스에는 프로세스 식별자를 저장하는 프로세스 ID 또는 PID라는 고유한 ID가 할당
  • 프로그램 카운터 : 프로세스를 위해 실행될 다음 명령어의 주소를 포함하는 카운터를 저장
  • 레지스터 : 누산기, 베이스, 레지스터 및 범용레지스터를 포함하는 CPU 레지스터에 있는 정보
  • 메모리 제한 : 운영체제에서 사용하는 메모리 관리 시스템에 대한 정보
    • 페이지 테이블 : 페이징 프로세스의 메모리 주소를 관리할 때 프로세스의 페이지 정보를 저장하고 있는 테이블
    • 세그먼트 테이블 : 프로세스를 논리적으로 잘라 메모리에 배치하는 방식을 세그멘테이션이라고 한다. 세그먼트 테이블은 이 세그먼트들의 실제 물리적 메모리 주소의 정보를 담고 있다.
  • 열린 파일 목록 : 프로세스를 위해 열린 파일 목록
  • Accountin 정보 : Process를 실행한 유저 정보
  • I/O 상태 정보 : Process에 할당된 물리적 장치 및 프로세스가 읽고 있는 파일에 관한 정보

Process 생성

프로세스 생성은 부모 프로세스가 연산을 통해 자식 프로세스를 만들어낸다. 생성된 자식 프로세스 또한 새로운 자식 프로세스를 만들 수 있으며, 이를 구별하기 위해 모든 프로세스는 각자 고유의 PID를 가지고 있다.
이렇게 생성된 프로세스 간의 관계는 하나의 큰 트리구조가 된다.

생성된 자식 프로세스는 각자 고유의 PID, 메모리, CPU 등 새 PCB가 할당되며 고유의 자원을 획득하게 된다.
이로 인하여 부모 프로세스의 자원 접근에 제한이 생기며 특수한 방법을 통해 공유할 수 있게 된다.

프로세스를 생성한 후 부모 프로세스는 다음과 같이 2가지 행동을 할 수 있다.

자식 프로세스가 끝날 때까지 기다린다 ( -> waiting queue )
자식 프로세스와 함께 동작 (멀티 프로세싱 환경)

자식 프로세스는 다음 중 하나의 프로세스가 된다.

  • 부모 프로세스와 동일한 새로운 프로세스 : 이 경우 부모 프로세스의 프로그램, 데이터가 완전 복사
  • 새로운 프로그램 실행 : 새로운 프로그램을 메모리에 load 하고 이를 실행

fork()

Linux/UNIX 환경에서 새로운 프로세스를 만드는 시스템 콜 함수

생성된 자식 프로세스는 부모 프로세스의 데이터와 프로그램이 완전 복사가 되어 똑같은 프로그램을 수행하는 프로세스가 된다.
멀티 프로세싱을 통해 부모, 자식 프로세스는 함께 동작한다.
fork() 함수는 부모 프로세스에서 자식의 PID를 반환하고, 자식 프로세스에서는 0을 반환하여 구분할 수 있도록 해준다.
fork

exec()

Linux/UNIX 환경에서 프로세스를 새로운 프로그램을 실행하는 프로세스로 대체하는 시스템 콜 함수

fork()와 다르게 자식 자식 프로세스를 생성하는 것이 아닌 현재 프로세스의 프로그램 코드를 새로운 프로그램 코드로 바꿔준다.
이로 인하여 프로그램 코드, 메모리, 파일 등 프로세스 자원이 새로 바뀌게 된다.
exec() 함수는 현재 프로세스가 완전히 새로운 프로그램을 실행하는 프로세스로 대체되므로 반환 값이 없다.
exec

보통 동작하는 방식은 fork()를 통해 자식 프로세스를 생성하고 자식 프로세스에서 exec()를 통해 새로운 프로그램을 돌리게 된다.
이때 부로 프로세스가 자식 프로세스가 끝나기를 기다려야 한다면 wait() 시스템 콜 함수를 이용하여 기다릴 수 있다.

Multi Process

두개 이상, 다수의 프로세서(CPU)가 협력적으로 하나 이상의 작업(Task)을 동시에 처리하는 것이다. (병렬처리)
각 프로세스 간 메모리 구분이 필요하거나 독립된 주소 공간을 가져야 할 경우 사용한다.

장점

  • 독립된 구조로 안전성이 높은 장점이 있다.
  • 프로세스 중 하나에 문제가 생겨도 다른 프로세스에 영향을 주지 않아, 작업속도가 느려지는 손해정도는 생기지만 정지되거나 하는 문제는 발생하지 않는다.
  • 여러개의 프로세스가 처리되어야 할 때 동일한 데이터를 사용하고, 이러한 데이터를 하나의 디스크에 두고 모든 프로세서(CPU)가 이를 공유하면 비용적으로 저렴하다.

문제점

  • 독립된 메모리 영역이기 때문에 작업량이 많을수록( Context Switching이 자주 일어나서 주소 공간의 공유가 잦을 경우) 오버헤드가 발생하여 성능저하가 발생 할 수 있다.
  • Context Switching 과정에서 캐시 메모리 초기화 등 무거운 작업이 진행되고 시간이 소모되는 등 오버헤드가 발생한다.

Context Switching

CPU는 한번에 하나의 프로세스만 실행 가능하다.
때문에 CPU에서 여러 프로세스를 돌아가면서 작업을 처리하는 데 이 과정을 Context Switching라 한다.
구체적으로, 동작 중인 프로세스가 대기를 하면서 해당 프로세스의 상태(Context)를 보관하고, 대기하고 있던 다음 순서의 프로세스가 동작하면서 이전에 보관했던 프로세스의 상태를 복구하는 작업을 말한다.

Process간 통신 방식 (IPC : Inter Process Communication)

프로세스 간 통신이란 프로세스가 서로 데이터를 주고받는 방법, 경로 등을 의미한다.
커널의 디자인에 따라 마이크로 커널, 나노 커널 등 통신이 많이 일어나는 디자인의 경우 IPC 방식이 성능을 크게 좌지우지할 수 있다.

Shared memory

운영체제의 도움을 받아 일부 영역의 메모리를 여러 프로세스가 동시에 접근할 수 있도록 권한을 받는다.
프로세스는 공유 메모리를 읽고 쓰면서 프로세스 간 통신을 하게 된다.
같은 메모리를 사용하는 환경에서 작동하므로 메모리에 접근하여 값을 변경하면 그 즉시 변경된 값이 반영되어 다른 프로세스들이 접근 시 변경된 값을 얻을 수 있다.
처음 메모리에 여러 프로세스가 접근 권한을 부여하는 작업에서만 커널 작업이 필요하고 이후엔 커널 동작이 필요 없다.

동작 과정

공유 메모리를 사용할 프로세스들 중 하나의 프로세스가 자신이 부여받은 메모리 영역 중 일부분을 선택
다른 프로세스 들은 공유할 메모리의 주소를 받아 이를 자신의 메모리 영역에 붙인다.
운영체제가 해당 프로세스들 간의 메모리 접근 제한을 풀어준다.
이후 프로세스들은 공유 메모리를 통해 통신

  • 운영체제는 더 이상 관여할 필요 없으며 프로세스가 종료 시 메모리를 반환하면 공유 메모리 또한 같이 반환하게 된다.

Message Passing

데이터가 하나의 메시지가 되어 프로세스 간 통신을 하게 된다.
충돌 위험이 없기 때문에 소량의 데이터 전송에 유리
명령만을 주고받는 분산 시스템, 마이크로/나노 커널 방식에 유리
공유 메모리 방식과 다르게 같은 환경에 있지 않아도 인터넷을 통해서 메시지를 주고받을 수 있다. (소켓)
생산자-소비자 모델의 공유 메모리 방식을 이용하면 동기화 작업이 필요 없지만 메시지 전달 방식은 동기화 작업이 필요한 경우가 많습니다. 비동기, 동기 방식에 따라 결정한다.

Send, Receive 2가지 명령에 의해 동작
  • Direct communication : send, receive 동작이 특정 프로세스를 지정하며 메시지를 직접 주고 받는다.
  • Indirect communication : 프로세스들 가운데 하나의 시스템, 네트워크 등을 두고 메시지를 중재하며 동작한다. 직접 전달 방식보다 더 유연하게 동작할 수 있으며 중재 시스템의 구현에 따라 보안성, 성능 등 다양한 처리가 가능해진다.
동기, 비동기

메시지 전달 방식은 동기화 작업이 필요한데, 동기방식과 비동기 방식이 있다.

동기(Blocking, Synchronous)
동기 Send : 메시지를 보내고 나면 받는 프로세스에게 메시지가 도착할 때까지 다른 작업을 할 수 없다.
동기 Receive : 메시지를 받기 전까지 해당 프로세스는 다른 작업을 하지 않고 멈춰 있어야 한다.

비동기(Nonblocking, Asynchronous)
비동기 Send : 메시지를 보내고 프로세스는 멈추지 않고 다음 작업을 진행한다.
비동기 Receive : 메시지를 받으면 해당 메시지가 유효한 내용인지 검사를 하고 처리

버퍼 형태
  • Unbounded buffer : 메모리 버퍼의 크기에 제한이 없으며 소비자 프로세스는 새 자원이 만들어질 때까지 기다려야 하며 생산자 프로세스는 항상 새로운 자원을 만들 수 있다. 이때 생산자 역할의 프로세스는 공유한 메모리 자원의 크기를 지정하여 이를 함께 소비자 프로세스에 알려주어야 한다.
  • Bounded buffer : 메모리 버퍼 크기에 제한이 있으며 소비자 프로세스는 버퍼가 빈 상황이면 새로운 자원이 채워질 때까지 기다리며 생산자 프로세스는 버퍼가 꽉 차 있으면 공간이 남을 때까지 기다려야 한다.

File 사용

텍스트 파일txt(혹은 다른 포멧의 파일)을 통해 데이터를 주고 받는 것도 IPC 기법 중 하나이다.

물론 이 방식은 문제가 많다. 이 방식은 실시간으로 직접 원하는 프로세스에 데이터 전달하는게 어렵기 때문이다.
디스크에서 데이터 파일을 읽고, 프로세스에 적재load되는 과정에서 컨텍스트 스위칭Context-switching, 인터럽트Interrupt 등 여러 일을 처리해야 하기 때문이다.

파이프(Pipe)

단방향 통신, 즉 부모 프로세스 → 자식 프로세스에게 일방적으로 통신하는 기법으로, fork()를 통해 자식 프로세스를 만들고 나서 부모의 데이터를 자식에게 보낸다. pipe

소켓(Socket)

많이 쓰이는 기법이자, 본래 목적이 IPC로 활용하기 위한 것은 아니지만, 충분히 활용이 가능하다.

본래 소켓은 네트워크 통신을 위한 기술이다. 기본적으로 클라이언트와 서버 등 두 개의 다른 컴퓨터 간의 네트워크 기반 통신을 위한 기술로, 네트워크 디바이스를 사용할 수 있는 시스템 콜이기도 하다.
소켓은 이렇게 클라이언트와 서버 뿐만 아니라, 하나의 컴퓨터 안에서 두 개의 프로세스 간의 통신 기법으로 활용하는 경우도 더러 있다.

ipcsocket

소켓을 사용하면 로컬 컴퓨터간의 통신 시 이렇게 계층을 타고 내려가면서 송신을 하고, 아래 계층부터 위로 올라가서 대상 프로세스가 수신을 하는 방식을 취하게 된다.


Thread 란?

사실 프로세스가 단일의 실행 쓰레드를 실행하는 프로그램이다. 진짜로 일하는 것은 쓰레드라고 보면 된다.

Multi Thread

하나의 프로세스에 여러 스레드로 자원을 공유하며 작업을 나누어 수행하는 것이다.
multiThread

장점

  • 시스템 자원소모 감소 (자원의 효율성 증대)
  • 프로세스를 생성하여 자원을 할당하는 시스템 콜이 줄어 자원을 효율적으로 관리할 수 있다.
  • 시스템 처리율 향상 (처리비용 감소)
  • 스레드 간 데이터를 주고 받는 것이 간단해지고 시스템 자원 소모가 줄어든다.
  • 스레드 사이 작업량이 작아 Context Switching이 빠르다. (캐시 메모리를 비울 필요가 없다.)
  • 간단한 통신 방법으로 프로그램 응답시간 단축
  • 스레드는 프로세스 내 스택영역을 제외한 메모리 영역을 공유하기에 통신 비용이 적다.
  • 힙 영역을 공유하므로 데이터를 주고 받을 수 있다.

문제점

  • 자원을 공유하기에 동기화 문제가 발생할 수 있다. (병목현상, 데드락 등)
  • 주의 깊은 설계가 필요하고 디버깅이 어렵다. (불필요 부분까지 동기화하면, 대기시간으로 인해 성능저하 발생)
  • 하나의 스레드에 문제가 생기면 전체 프로세스가 영향을 받는다.
  • 단일 프로세스 시스템의 경우 효과를 기대하기 어렵다.

Process와 Thread의 차이

  • 프로세스는 현재 실행되고 있는 프로그램으로 메모리에 올라와서 독립적인 메모리 공간을 가진다.
  • 쓰레드는 프로세스 내에서 실행되는 흐름으로 프로세스 자원을 공유한다.

멀티 스레드 vs 멀티 프로세스

  • 멀티 스레드는 멀티 프로세스보다 적은 메모리 공간을 차지하고 Context Switching이 빠른 장점이 있지만, 동기화 문제와 하나의 스레드 장애로 전체 스레드가 종료 될 위험을 갖고 있다.
  • 멀티 프로세스는 하나의 프로세스가 죽더라도 다른 프로세스에 영향을 주지 않아 안정성이 높지만, 멀티 스레드보다 많은 메모리공간과 CPU 시간을 차지하는 단점이 있다.
  • 두 방법은 동시에 여러 작업을 수행하는 점에서 동일하지만, 각각의 장단이 있으므로 적용하는 시스템에 따라 적합한 동작 방식을 선택하고 적용해야 한다.

왜 멀티 스레드로 나눠가며 할까?

  • 운영체제가 시스템 자원을 효율적으로 관리하기 위해 스레드를 사용한다.
  • 멀티 프로세스로 실행되는 작업을 멀티 스레드로 실행할 경우, 프로세스를 생성하여 자원을 할당하는 시스템 콜이 줄어들어 자원을 효율적으로 관리할 수 있다.
  • 또한, 프로세스 간의 통신보다 스레드 간의 통신 비용이 적으므로 작업들 간 통신의 부담이 줄어든다. (처리비용 감소. 프로세스는 독립구조이기 때문)

그렇다면 무조건 멀티 스레드가 좋은가?

스레드를 활용하면 자원의 효율성이 증가하기도 하지만, 스레드 간의 자원 공유는 전역 변수를 이용하므로 동기화 문제가 발생 할 수 있으므로 프로그래머의 주의가 필요하다.


좀비 & 고아 프로세스

좀비 프로세스

자식 프로세스가 부모 프로세스보다 먼저 죽는 경우 부모 프로세스가 종료 상태를 회수하기 위해 커널이 자식 프로세스의 최소한의 정보(PID, 종료 상태 등, 리눅스의 경우 커널에서 사용하는 구조체)를 남겨 둔다.
부모 프로세스는 wait 함수를 호출하여 이 상태를 회수하면 남은 모든 정보가 제거되어 자식 프로세스는 완전히 소멸하게 된다.

위와 같은 진행상황에서 부모 프로세스가 wait 함수를 호출하지 않아 최소한의 정보가 메모리에 남아 있는 경우를 좀비 프로세스라고 한다.
좀비 프로세스는 최소한의 정보만을 가지고 있어 큰 성능 저하를 야기하지 않지만, 운영체제는 한정된 PID를 가지고 있으므로 좀비 프로세스가 PID를 차지하며 다른 프로세스 실행을 방해하게 된다.
따라서 부모 프로세스는 좀비 프로세스 생성을 방지하기 위해 wait 함수를 호출하여 상태를 회수하여야 한다.

커널 입장에서 좀비 프로세스는 성능 저하를 일으킨다고 볼 수 있다.
프로세스 스케줄링에 있어서 queue에 걸려있는 프로세스의 양이 증가하고 커널 구조체를 유지하기 위한 비용 또한 무시할 수 없다.

좀비 프로세스를 다음과 같은 방법으로 관리할 수 있다.

  • wait : 간단하게 부모 프로세스에서 wait 함수를 호출하여 좀비 프로세스를 없앨 수 있다.
  • signal, wait : wait 함수는 블록 모드로 동작하는 함수이므로 부모 프로세스는 wait함수를 호출한 즉시 동작을 멈추게 된다. 이를 방지하기 위해 시그널 도구를 활용하여 자식 프로세스가 종료될 경우 발생하는 SIGCHLD 시그널에 해당하는 핸들러를 만들고 해당 핸들러에서 wait 함수를 호출하면 된다.

고아 프로세스(Orphan)

부모 프로세스가 자식 프로세스보다 먼저 종료되는 경우 부모 프로세스가 없는 자식 프로세스를 말한다.
운영체제는 이러한 고아 프로세스를 허용하지 않으며 부모 프로세스가 먼저 종료되면 자식 프로세스의 새로운 부모 프로세스로 init(PID = 1)가 설정된다.

init 프로세스는 자식 프로세스가 종료될 때까지 기다린 후 wait 함수를 호출하여 고아 프로세스의 종료 상태를 회수하여 좀비 프로세스가 되는 것을 방지한다.
고아 프로세스는 프로세스 자신이 시스템의 자원을 낭비할 수 있고, 시스템이 프로세스가 종료될 때까지 추적을 해야 하기 때문에 성능 저하의 원인이 된다.

고아 프로세스는 init 프로세스가 관리를 해 주지만 성능 저하를 방지하기 위해 부모 프로세스가 종료되기 전에 모든 자식 프로세스를 wait 해 주는 것이 좋다.

바이트오더링(Byte Ordering)

바이트 오더링에 대해 자세히 알아보자.

바이트 오더링 이란?

바이트 오더링(Byte Ordering)은 데이터가 바이트(Byte) 단위로 메모리에 저장되는 순서를 말한다.

크게 Big-Endian 방식과 Little-Endian 방식이 존재하며 각 CPU 벤더에 의존적인 특징을 가지고 있다.

2 바이트 이상의 크기를 가진 자료형을 저장할 때부터 차이가 난다.

BYTE    b       =   0x12;

WORD    w       =   0x1234;

DWORD   dw      =   0x12345678;

char    str[]   =   "abcde"; 

TypeNameSizeBig-EndianLittle-Endian
BYTEb1[12][12]
WORDw2[12][34][34][12]
DWORDdw4[12][34][56][78][78][56][34][12]
char[]str6[61][62][63][64][65][00][61][62][63][64][65][00]

Big-Endian 방식

상위 바이트의 값이 메모리에 먼저 표시되는 방법 (번지수가 작은 위치)

사용되는 계열 : 대형 UNIX 서버에 사용되는 RISC 계열의 CPU

Bit-Endian

네트워크 데이터 통신에서는 네트워크 바이트 순서(Network Byte Order, 즉 Big-Endian)를 따르도록 데이터의 바이트 순서를 변경해야 한다.
(TCP/IP, XNS, SNA 규약은 16비트와 32비트 정수에서 Big-Endian 방식을 사용함)

따라서 시스템이 Little-Endian 방식을 사용할 경우 네트워크를 통해 데이터를 전송하기 전에 Big-Endian 방식으로 데이터를 변경해서 보내야만 하고 받을 때는 Little-Endian 시스템은 전송되어 오는 데이터를 역순으로 조합해야 함.

Little-Endian 방식

하위 바이트의 값이 메모리상에 먼저 표시되는 방법 (번지수가 작은 위치)

사용되는 계열 : Intel 계열의 CPU

Little-Endian

두 Endian 방식의 장단점

Big-Endian 방식은 소프트웨어의 디버그를 편하게 해 주는 경향이 있다.
사람이 숫자를 읽고 쓰는 방법과 같기 때문에 디버깅 과정에서 메모리의 값을 보기 편하다.

예를 들어 0x59654148 은 빅 엔디언으로 59 65 41 48 로 표현한다.

반대로 Little-Endian 방식 은 메모리에 저장된 값의 하위 바이트들만 사용할 때 별도의 계산이 필요 없다는 장점이 있다.

예를 들어 32비트 숫자인 0x2A 는 Little-Endian 방식으로 표현하면 2A 00 00 00 이 되는데 이 표현에서 앞의 두 바이트 또는 한 바이트만 떼어 내면 하위 16 비트 또는 8 비트를 바로 얻을 수 있다.

반면 32bit Big-Endian 방식 환경에서는 하위 16 비트나 8 비트 값을 얻기 위해서는 변수 주소에 2바이트 또는 3바이트를 더해야 한다.

보통 변수의 첫 바이트를 그 변수의 주소로 삼기 때문에 이런 성질은 종종 프로그래밍을 편하게 하는 반면 Little-Endian 방식 환경의 프로그래머가 Big-Endian 방식 환경에서 종종 실수를 일으키는 한 이유이기도 하다.

또한, 가산기가 덧셈을 하는 과정은 LSB 로부터 시작하여 자리 올림을 계산해야 하므로 첫 번째 바이트가 LSB 인 Little-Endian 방식에서는 가산기 설계가 조금 더 단순해진다.

Big-Endian 방식에서는 가산기가 덧셈을 할때 마지막 바이트로부터 시작하여 첫 번째 바이트까지 역방향으로 진행해야 한다.

그러나 오늘날의 프로세서는 여러개의 바이트를 동시에 읽어들여 동시에 덧셈을 수행하는 구조를 갖고 있어 두 Endian 방식 사이에 사실상 차이가 없다.

[참고 사이트] : https://ko.wikipedia.org/wiki/%EC%97%94%EB%94%94%EC%96%B8

시놀로지 NAS

Synology 사용하면서 익힌 활용법 정리

왜 NAS?

요즘에는 사람들이 NAS를 많이들 활용하고 있다.
NAS는 Network Attached Storage의 약자로 네트워크에 연결된 저장장치로 사람들이 흔히 쓰는 클라우드의 기능을 하고 있는 일종의 서버이다.

단순히 클라우드 서비스와 같이 저장소로 활용을 많이 하고 있지만, 그 뿐만이 아닌 서버 운영, DB, 공유 등의 다양한 기능을 제공하기도 한다.
또한 어디서든 외장하드 같은 것을 번거롭게 들고 다니지 않아도 된다.
이 부분이 내가 NAS를 구매한 이유 중 하나이다.

사실 NAS를 구매한건 22년 05월로 사용한지는 벌써 반년이 지났지만 이제서야 글로 작성하면서 사용했던 방식이나 활용법을 글로 적어보려고 한다…ㅎ
구매한 이유는 가족들의 사진을 저장하고 어디서든 공유하면서 사용하기 위한 목적이 우선적이면서 무료 클라우드가 가득 찼기에 매달 요금을 내면서 사용하기 싫었기 때문에 큰 출혈이 있더라고 구매하였다.

그러면서 더더욱 욕심을 내며 사이드 프로젝트를 위한 서버로도 활용하면 좋을 것 같다는 생각을 했기 때문에 관련 기능을 지원하는 NAS를 찾아보았다.
(실제로 이 글을 쓰는 지금 서버로 활용하여 개발한 프로젝트가 2~3개는 된다.)

Synology

여러가지 장비를 비교하며 찾아보다가 Synology 사의 장비를 구매하기로 결정했다.
그 이유는 DSM센터를 통해서 사용하기 편리한 UI를 제공하고 있으며, Synology사의 다양한 내부 패키지 기능을 활용하면 사용 범위성이 무궁무진하기 때문이다.

현재 구매한 NAS는 DS220+ 2Bay 제품으로, 가격적으로도 그렇고 내가 원하는 기능 정도로만 사용하기에 적당한 제품이다.
DS220+

내가 NAS를 사용하면서 현재 쓰고 있는 기능들은 아래와 같다.

  • DS Photo를 통해 가족들이랑 연결해서 모바일의 사진을 저장하고 공유하는 기능
  • Video Station 기능을 통해 나만의 OTT 서비스
  • 개인 파일들의 저장
  • Note Station을 통한 나만의 노트 정리
  • 웹 서비스 구동
  • MariaDB 구동
  • 안드로이드 앱을 위한 Spring 서버 (사이드 프로젝트)
  • Docker 활용하기

이제와서 봐도 참 알차게 사용한것 같아서 뿌듯하네!

이렇게 다양하게 활용하면서 익혔던 기능이나 까먹기 쉬운 기능들을 정리하려고 한다.

Maven? Gradle?

스프링 프로젝트에서 활용되는 maven과 gradle에 대해 알아본다.

Maven의 경우에는 스프링 프로젝트에서 pom.xml이란 이름으로 다루고 있다.

Gradle은 스프링부트, 안드로이드에서 쓰는걸로 기억하고 있는데, 이것이 맞는 것인가?! 바로 알아보자

Maven 이란?

프로젝트를 진행하게 되면 단순히 자신이 작성한 코드만으로 개발하는 것이 아니라 많은 라이브러리들을 활용해서 개발을 하게 된다.
세상에 많은 천재들이 개발한 라이브러리를 활용해서 개발을 하게 되면 개발 시간도 단축될뿐 아니라 안정성도 그만큼 보장되지 않겠는가! 적극 활용한다!👍

이 때 사용되는 라이브러리들의 수가 수십개가 훌쩍 넘어가버리는 일이 발생해 이 많은 라이브러리들을 관리하는 것이 힘들어지는 경우가 종종 발생하게 된다.
Maven은 이러한 문제를 해결해 줄 수 있는 도구이다.
Maven은 내가 사용할 라이브러리 뿐만 아니라 해당 라이브러리가 작동하는데 필요한 다른 라이브러리들까지 관리하여 네트워크를 통해 자동으로 다운 받아 준다.

Maven은 프로젝트의 전체적인 라이프사이클을 관리하는 도구이며, 많은 편리함과 이점이 있어 널리 사용되고 있다.
Maven은 JDK설치와 같이 설치할 수 있다. 환경변수를 잡아주면 cmd에서 mvn -version을 통해 버전을 알 수 있고 설치가 가능하다.
설치는 메이븐 홈페이지에서 할 수 있다.

Maven의 Lifecycle

maven 에서는 미리 정의하고 있는 빌드 순서가 있으며 이 순서를 라이프사이클이라고 한다. 라이프 사이클의 각 빌드 단계를 Phase라고 하는데, 이런 Phase들은 의존관계를 가지고 있다.

  • Clean : 이전 빌드에서 생성된 파일들을 삭제하는 단계
  • Validate : 프로젝트가 올바른지 확인하고 필요한 모든 정보를 사용할 수 있는지 확인하는 단계
  • Compile : 프로젝트의 소스코드를 컴파일하는 단계
  • Test : 단위 테스트를 수행하는 단계
    • 테스트 실패 시, 빌드 실패로 처리
    • 스킵 가능
  • Package : 실제 컴파일된 소스 코드와 리소스들을 jar등의 배포를 위한 패키지로 만드는 단계
  • Verify : 통합테스트 결과에 대한 검사를 실행하여 품질 기준을 충족하는지 확인하는 단계
  • Install : 패키지를 로컬 저장소에 설치하는 단계
  • Site : 프로젝트 문서를 생성하는 단계
  • Deploy : 만들어진 Package를 원격 저장소에 release하는 단계

위 9개의 라이프 사이클 말고도 더 많은 종류가 존재한다.
이를 크게 Clean, Build, Site 세 가지로 나누고 있다.
각 단계를 모두 수행하는 것이 아니라 원하는 단계까지만 수행할 수도 있으며 test단계는 큰 프로젝트의 경우에 몇 시간이 소요될 수 있으니 수행하지 않도록 스킵이 가능하다.

Phase와 Goal

위에서 잠깐 언급헀던 Phase는 Maven의 Build LifeCycle의 각각의 단계를 의미한다. 각각의 Phase는 의존관계를 가지고 있어서 해당 Phase가 수행되려면 선행 단계의 Phase가 모두 수행되어야 한다.

메이븐에서 제공되는 모든 기능은 플러그인 기반으로 동작하는데 메이븐은 라이프 사이클에 포함 되어있는 Phase마저도 플러그인을 통해 실질적인 작업이 수행된다. 즉 각가의 Phase는 어떤 일을 할지 정의하지 않고 어떤 플러그인의 Goal을 실행할지 설정한다.

메이븐에서는 하나의 플러그인에서 여러작업을 수행할 수 있도록 지원하며, 플러그인에서 실행할 수 있는 각각의 기능을 Goal이라고 한다.
플러그인의 Goal을 실행하는 방법은 다음과 같다.

  • mvn groupId:artifactId:version:goal (아래와 같이 생략 가능)
  • mvn plugin:goal

POM(Project Object Model)

pom은 이름 그대로 Project Object Model의 정보를 담고 있는 파일이다. 이 파일에서 주요하게 다루는 기능들은 다음과 같다.

  • 프로젝트 정보 : 프로젝트의 이름, 개발자 목록, 라이센스 등
  • 빌드 설정 : 소스, 리소스, 라이프 사이클별 실행한 플러그인(Goal)등 빌드와 관련된 설정
  • 빌드 환경 : 사용자 환셩 별로 달라질 수 있는 프로파일 정보
  • POM연관 정보 : 의존 프로젝트(모듈), 상위 프로젝트, 포함하고 있는 하위 모듈 등

POM은 pom.xml파일을 말하며 Maven의 기능을 이용하기 위해 사용된다.


Gradle 이란?

Gradle이란 기본적으로 빌드 배포 도구(Build Tool)이다.
안드로이드 앱을 개발할때 필요한 공식 빌드시스템이기도 하며 JAVA, C/C++, Python 등을 지원한다.

빌드툴인 Ant Builder와 그루비 스크립트를 기반으로 구축되어 기존 Ant의 역할과 배포 스크립트의 기능을 모두 사용가능하다.

Maven의 경우 XML로 라이브러리를 정의하고 활용하도록 되어 있으나, Gradle의 경우 별도의 빌드스크립트를 통하여 사용할 어플리케이션 버전, 라이브러리등의 항목을 설정 할 수 있다.

장점으로는 스크립트 언어로 구성되어 있기 때문에 XML과 달리 변수선언, if else for 등의 로직이 구현 가능하여 간결하게 구성이 가능하다.

  • 라이브러리 관리 : Maven repository를 동일하게 사용할 수 있어서 설정된 서버를 통하여 라이브러리를 다운로드 받아 모두 동일한 의존성을 가진 환경을 수정할 수 있다. 또한 자신이 추가한 라이브러리도 repo 서버에 올릴 수 있다.
  • 프로젝트 관리 : 모든 프로젝트가 일관된 디렉토리 구조를 가지고 빌드 프로세스를 유지하도록 도와준다.
  • 단위 테스트 시 의존성 관리 : junit 등을 사용하기 위해서 명시한다.

Gradle 장점

Maven에는 Gradle과 비교문서가 없지만, Gradle에는 비교문서가 있다.
그만큼 Maven의 모든 기능을 포함하고 있고, 더 뛰어나다고 표현하는것일까?
Gradle이 시기적으로 늦게 나온만큼 사용성, 성능 등 비교적 뛰어난 스펙을 가지고 있다.

그래서 Gradle이 Maven보다 좋은점은?

  • Build라는 동적인 요소를 XML로 정의하기에는 어려운 부분이 많다.
    • 설정 내용이 길어지고 가독성이 떨어짐
    • 의존관계가 복잡한 프로젝트 설정하기에는 부적절
    • 상속구조를 이용한 멀티 모듈 구현
    • 특정 설정을 소수의 모듈에서 공유하기 위해서는 부모 프로젝트를 생성하여 상속하게 해야함 (상속의 단점이 생김)
  • Gradle은 그루비를 사용하기 때문에, 동적인 빌드는 Groovy 스크립트로 플러그인을 호출하거나 직접 코드를 짜면 된다.
    • Configuration Injection 방식을 사용해서 공통 모듈을 상속해서 사용하는 단점을 커버했다.
    • 설정 주입시 프로젝트의 조건을 체크할 수 있어서 프로젝트별로 주입되는 설정을 다르게 할 수 있다.

Gradle은 Maven보다 최대 100배 빠르다고 한다.


그래서 결론은?

Gradle이 출시되었을 때는 Maven이 지원하는 Scope를 지원하지 않았고 성능면에서도 앞설것이 없었다. Ant의 유연한 구조적 장점과 Maven의 편리한 의존성 관리 기능을 합쳐놓은 것만으로도 많은 인기를 얻었던 Gradle은 버전이 올라가며 성능이라는 장점까지 더해지면서 대세가 되었다.

리드미컬하게 테스트를 진행하고 민첩한 지속적 배포를 생각하고 있다면 새로운 배움이 필요하더라도 Gradle을 사용하는것이 좋다고 생각한다.

스프링 프로젝트

스프링의 jpa + lombok 방식 활용하기

JPA, 자바 지속성 API(JAVA Persistence API)

자바 플랫폼 SE와 EE를 사용하는 응용프로그래메서 관계형 데이터베이스의 관리를 표현하는 Java API이다. 이전에 SSAFY를 다니며 배운 경험은 있지만 다시 한 번 사용하면서 정리해보기로 한다.

lombok

getter, setter 등의 반복 메서드를 자동으로 연결하고 도구를 빌드하여 Java를 향상시키는 Java 라이브러리이다.
lombok

1. Dependency 추가 (jpa, lombok, mariaDB)

Maven의 경우 pom.xml에 추가

<!-- JPA -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<!-- lombok -->
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <optional>true</optional>
</dependency>

<!-- mariaDB -->
<dependency>
  <groupId>org.mariadb.jdbc</groupId>
  <artifactId>mariadb-java-client</artifactId>
</dependency>

gradle의 경우 build.gradle에 추가

dependencies {
  // JPA
  implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
  // lombok
  implementation 'org.projectlombok:lombok'
  // mariaDB
  implementation 'org.mariadb.jdbc:mariadb-java-client'
}

여기서 의문점이 좀 들었다.
Maven과 Gradle의 차이점은 무엇일까? 바로 알아보자
-> Maven과 Gradle

2. 데이터베이스 설정

application.properties

spring.datasource.driverClassName=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://IP:3306/databaseName
spring.datasource.username=user
spring.datasource.password=pwd

aplication.yml

spring:
  datasource:
    driverClassName: org.mariadb.jdbc.Driver
    url: jdbc:mariadb://IP:3306/databaseName
    username: user
    password: pwd

3. 재사용될 컬럼을 추상 클래스로 작성

CommonVo.java

import java.time.LocalDateTime;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import org.hibernate.annotations.CreationTimestamp;
import lombok.Data;

// Getter, Setter Auto Create
@Data
// 공통 매핑 정보가 필요할 때, 부모 클래스에 선언하고 속성만 상속 받아서 사용하고 싶을 때 사용한다.
@MappedSuperclass
public abstract class CommonVo {

  // register id
  private String regId;

  // modify id
  private String modId;

  // register Date time
  @CreationTimestamp
  /*
  * 보통 JPA는 SAVE시에 모든 칼럼을 INSERT한다.
  * 그럴 경우, NOT NULL로 설정된 칼럼은 기본값으로 삽입되는 것이 아닌 NULL로 삽입을 시도한다.
  * 이로 인해 에러가 발생하는데, 이럴 경우에 아예 쿼리에서 빼버려서 실행이 안되게 만들 수 있다.
  * 쿼리에서 제외된 칼럼은 DB에 지정된 default값으로 삽입이 된다.
  * 특정 칼럼을 제외하고 save하는 방법은 다음과 같다.
  * insertable = false, updatable = false
  */
  @Column(updatable = false)
  private LocalDateTime regDtm;

  // modify Date time
  @CreationTimestamp
  private LocalDateTime modDtm;
}

4. CommonVo를 상속받은 MemberVo 작성

MemberVo.java

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import com.melon.boot.common.vo.CommonVo;
import lombok.Data;

// Getter, Setter Auto Create
@Data
@Entity(name = "member")
public class MemberVo extends CommonVo {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long mbrSeq;
  private String id;
  private String pwd;
  private String name;
  private String addrLoad;
}

5. JpaRepository를 상속받은 interface 작성

MemberRepository.java

package com.melon.boot.member.service.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import com.melon.boot.member.vo.MemberVo;

public interface MemberRepository extends JpaRepository<MemberVo, Long> {
}

6. Service Class 작성

MemberService.java

import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.melon.boot.member.service.repository.MemberRepository;
import com.melon.boot.member.vo.MemberVo;

@Service
public class MemberService {

  @Autowired
  private MemberRepository memberRepository;

  // INSERT
  public MemberVo insert(MemberVo memberVo) throws Exception {
    return memberRepository.save(memberVo);
  }

  // SELECT LIST
  public List<MemberVo> findAll() throws Exception {
    return memberRepository.findAll();
  }

  // SELECT BY ID
  public Optional<MemberVo> findById(Long mbrSeq) throws Exception {
    return memberRepository.findById(mbrSeq);
  }

  // UPDATE
  public MemberVo updateById(MemberVo memberVo) throws Exception {
    Optional<MemberVo> e = memberRepository.findById(memberVo.getMbrSeq());

    MemberVo resultMember = null;
    if(e.isPresent()) {
      resultMember = memberRepository.save(memberVo);
    }
    return resultMember;
  }

  // DELETE
  public void deleteById(Long mbrSeq) throws Exception {
    memberRepository.deleteById(mbrSeq);
  }
}

7. Controller Class 작성

MemberController.java

import java.time.LocalDateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.melon.boot.member.service.MemberService;
import com.melon.boot.member.vo.MemberVo;

@Controller
@RequestMapping("/member")
public class MemberController {

  @Autowired
  MemberService memberService;

  @GetMapping("/insert")
  public void insertMember() throws Exception {
    try {
      MemberVo memberVo = new MemberVo();

      memberService.insert(memberVo);
    } catch(Exception e) {
      e.printStackTrace();
    }
  }

  @GetMapping("/selectList")
  public void selectMemberList() throws Exception {
    try {
      memberService.findAll();
    } catch(Exception e) {
      e.printStackTrace();
    }
  }

  @GetMapping("/select")
  public void selectMember() throws Exception {
    try {
      memberService.findById((long) 1);
    } catch(Exception e) {
      e.printStackTrace();
    }
  }

  @GetMapping("/update")
  public void updateMember() throws Exception {
    try {
      MemberVo memberVo = new MemberVo();

      memberService.updateById(memberVo);
    } catch(Exception e) {
      e.printStackTrace();
    }
  }

  @GetMapping("/delete")
  public void deleteMember(MemberVo memberVo) throws Exception {
    try {
      memberService.deleteById(memberVo.getMbrSeq);
    } catch(Exception e) {
      e.printStackTrace();
    }
  }
}

8. 테스트 URL

  • /member/insert
  • /member/selectList
  • /member/select
  • /member/update
  • /member/delete

위에서처럼 jpa, lombok, mariadb를 사용해서 CRUD 통신하는 서버를 만들어보았다.
이제 이것을 바탕으로 GLotto에 해당하는 데이터 테이블을 만들고 데이터를 넣은다음 돌아가는 서버를 만들 수 있겠다.

사이드 프로젝트 시작?!

사이드 프로젝트를 시작해보았다.

사이드 프로젝트를 시작하게된 계기

사실 사이드 프로젝트를 시작하려고 생각하고 메모 했던 내용은 늘 있었다. 그럼에도 시간이 없다는 핑계로.. 아이디어가 없다는 핑계로.. 처음부터 만들어 볼 여유가 좀처럼 생기지 않았다.
그래도 뭔가 작은 프로젝트를 만들기 시작하고, 회사 일에도 여유가 생기고부터 만들어보고 싶었던것들을 리스트화하고 이것을 정리하면서 만들어갈 필요성을 느꼈다.
뭐, 이것도 결국에는 내 경험치가 될 것이니까?

사이드 프로젝트 계획

  • 리스트 업
  • 실현 가능성을 기반으로 우선순위 정리
  • 설계
  • 프로젝트 별 관리

리스트 업

중간 중간 생각나는대로 리스트업을 업데이트 할 예정인데 우선 정리한것들은 이렇다.

listup

NAS Note에 정리한 아이디어의 일부인데 진작에 좀 활용할껄 너무 늦은거 아니니..

계획

우선적으로 포토샵을 아직 배우는중이기 때문에 UI작업이 제일 까다롭지 않을것 같은 로또앱을 출시해보려고 한다.
해당 내용은 다른 포스트로 업로드 할 예정이다.

Pagination