카테고리 없음 2024. 5. 10. 07:00

스마트도서관 국립중앙도서관의 통합도서서비스상 대출정지회원 오류

스마트도서관 무인기기에서 책 대출을 하려고 예약을 미리 해두었다.

책이 준비됐다는 카톡 메시지를 보고 무인기기로 가서 회원번호를 찍었더니, 아래와 같이 오류가 나왔다.

책 반납을 안 한 게 있었나 싶어서 국립중앙도서관에 전화로 문의했더니, 예전에 이용하던 구립도서관과의 전산 미동기화때문이었다.

상담원분이 수동으로 처리해주셔서 잘 해결됐는데, 시스템이 어떻게 되어있길래 수동으로 동기화를 하나 싶었음... 화가 났다거나 한 게 아니라 단순 궁금증..

해당 국립중앙도서관 전화번호 : 02-590-0650

 

Web 2024. 4. 23. 13:26

접속할 때마다 열받는 사이트 중 하나... 뭔가 안 된다 싶으면 바로 지원센터로 전화할 것

 

1. Windows + R 키를 눌러서 실행 창을 띄우고 %localappdata% 입력 (혹은 파일탐색기에서 C:\Users\유저명\AppData\Local 으로 접근)

2. 파일탐색기가 열리면 court 폴더 내의 파일 2개 삭제

3. 인터넷 등기소에서 발급버튼 클릭 후 테스트 출력 진행

4. 발급 버튼을 한 번 더 클릭

 

 

'Web' 카테고리의 다른 글

구글 검색으로 Tistory 접속 시 400 에러 발생할 때  (0) 2023.04.22
티스토리 마크다운 CSS 적용  (0) 2021.02.21
Utility 2023. 6. 26. 16:24

DataGrip 스키마를 선택해도 Table이 제대로 안 보일 때

  • 스키마를 선택해도 Table 등 DB Object가 정상적으로 보이지 않을 경우, 캐시를 지워주면 되더라..

  • 위치 : 연결된 Data Source 우클릭 > Diagnostics > Forget Cached Schemas (기준 : 2022.3.3 버전)

Web 2023. 4. 22. 23:20

구글 검색으로 Tistory 접속 시 400 에러 발생할 때

  • 브라우저 캐시 문제였다.
  • 에러 페이지에서 F12로 개발자 도구를 열고, Application 탭의 Storage > Cookies 에서 tistory.com 사이트를 우클릭하여 Clear하면 해결된다.

MacOS 2023. 4. 5. 17:58

QuickLookUIService 프로세스를 재시작하면 된다.

 

 

(Ventura 13.3 기준)

  1. QuickLookUIService 프로세스 종료
    • 활성 상태 보기 앱에서 quicklookuiservice 프로세스를 찾아서 강제종료시킨다.

  1. QuickLookUIService 프로세스 시작
    • 다음 경로의 파일을 실행시키면 된다.
/System/Library/Frameworks/QuickLookUI.framework/Versions/A/XPCServices/QuickLookUIService.xpc/Contents/MacOS/QuickLookUIService

 

Windows/Registry 2023. 3. 15. 01:44

1. 실행 - regedit 입력 후 관리자로 실행

 

2. 다음 경로로 이동

  컴퓨터\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Citrix\ICA Client\Engine\Lockdown Profiles\All Regions\Lockdown\Virtual Channels\Keyboard

 

3. TransparentKeyPassthrough 의 값을 Remote 로 변경

 

4. Citrix Workspace 연결 해제 후 다시 연결

Windows 2023. 1. 31. 17:42

윈도우 Magic Trackpad 2 사용 전 설치

  • 트랙패드를 윈도우에 그냥 연결하면, 클릭 및 이동은 가능하나 제스처 사용이 불가하여 드라이버를 설치했다.

설치 과정

1. 다음 링크에서 우측 Releases의 최신 버전 클릭

  - https://github.com/imbushuo/mac-precision-touchpad

2. amd64 혹은 arm64 CPU에 맞는 파일 다운로드 후 압축 해제

3. PC에 연결 중인 트랙패드가 있다면 연결 해제하기

4. AmtPtpDevice.inf 파일 우클릭 -> 설치 클릭  (윈도우 11은 "더 많은 옵션 표시" 를 눌러야 나온다.)

 

5. 설치 후 별 다른 창이 나오지 않는다. 트랙패드 연결 후 정상적으로 작동되는 걸 볼 수 있다.

Git 2023. 1. 15. 17:53

Gitlab 서버 EXTERNAL_URL 변경

  • Linux 환경에서 Gitlab 서버 설치 이후 EXTERNAL_URL 변경을 위해서는, Gitlab 루비 파일의 설정을 변경하고 Gitlab을 재시작하면 된다.

    /etc/gitlab/gitlab.rb

    ...
    external_url "https://example.com/gitlab"
    ...
  • Gitlab 재시작

    $ sudo gitlab-ctl reconfigure
    $ sudo gitlab-ctl restart

참고

'Git' 카테고리의 다른 글

Github 계정 2개 SSH 연결  (0) 2021.07.06
Git Config  (0) 2021.02.28
git clone invalid path 에러  (0) 2021.02.28
Java 2023. 1. 14. 19:39

JIT 컴파일

정의

  • Just-In-Time Compilation (= Dynamic Translation, 동적 번역)
  • 프로그램을 실행하는 시점(런타임)에 기계어로 번역하는 컴파일 기법이다.
    • 실행 시점에 인터프리트 방식으로 코드를 읽어가면서 기계어 코드를 생성한다.
    • 생성된 기계어 코드를 캐싱하여, 재사용 시에는 캐싱된 기계어 코드를 사용한다.

Java의 경우

  • Java 컴파일러 : 자바 프로그램 코드 → 바이트코드
  • JIT 컴파일러 : 바이트코드 → 기계어 코드

장점 (사용 이유)

  • Only 인터프리터 방식보다는 성능이 좋고, Only 정적 컴파일 방식보다는 이식성이 좋다.
  • 즉, 정적 컴파일러의 성능과 인터프리터 언어의 편의성을 모두 추구한다.

의외의 장점

정적 컴파일러로 번역한 결과보다 성능이 더 좋을 수 있다.

  • 실행 환경에 맞추어 최적화된 코드를 생성할 수 있다.
    • CPU 세대마다 지원하는 명령어가 다를 수 있는데, 더 효율적인 명령어로 수행 가능한 작업은 해당 명령어를 통해 수행하도록 할 수 있다. (ex. 인텔 x86 CPU의 MMX 명령어)
    • 실행 환경의 캐시, 메모리 크기 등 런타임에만 알 수 있는 H/W, S/W 정보를 활용할 수 있기 때문에 정적 컴파일보다 좋은 성능의 코드를 생성할 가능성이 있다.
  • 가상 함수 테이블을 통해 가상 메서드가 간접 호출될 때, 해당 메서드를 오버라이드하는 서브(자식) 클래스가 존재하지 않을 경우에 간접 호출을 정적 바인딩(Static Binding)으로 호출하거나 인라인으로 전개할 수 있다고 한다.

참고

Windows 2023. 1. 5. 11:03

Windows 11 작업표시줄 Webex 이 창의 공유 버튼 비활성화

  • Webex 온라인 미팅 시 작업표시줄에서 그룹화된 프로그램 선택 시 이 창의 공유 버튼이 있어서 불편함을 느꼈다.

  • 윈도우 11 설정 중, 개인 설정 > 작업 표시줄 > 작업 표시줄 동작 에서 작업 표시줄의 모든 창 공유 옵션을 체크해제하면 된다.

MacOS 2023. 1. 4. 02:02

MacOS VoiceOver 단축키 비활성화

  • 맥북을 사용하다가 Command + F5 를 잘못 눌렀더니 VoiceOver가 호출되어 깜짝 놀랐다.

  • 잘 사용하는 기능이 아니어서, 단축키를 비활성화하기로 결정

설정 경로

  • 시스템 환경설정 > 키보드 > 단축키 > 손쉬운 사용 > VoiceOver 켜거나 끄기 체크 해제

MacOS 2023. 1. 4. 00:39

MacOS hosts file 경로

  • 경로는 아래와 같으며, 윈도우의 hosts 파일과 같이 IP Domain 형식으로 적으면 된다. (sudo 권한 필요)

    $ sudo vi /etc/hosts
  • hosts 파일 수정 후 바로 적용하려면 다음 명령어를 사용하여 DNS 캐시를 비워야 한다.

    $ dscacheutil -flushcache
MacOS 2023. 1. 1. 00:24

macOS 특정 IP 열린 포트번호 확인

  • 개방 와이파이를 사용하다가, 공유기 게이트웨이 IP가 http로 열리지 않아서, 특정 IP에 대한 열린 포트 확인하는 스크립트가 있으면 좋을 것 같다고 생각했다.
  1. brew 설치 (Homebrew)

    $ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  2. tcping 설치

    $ brew install tcping
  3. 셸 스크립트 작성 (백그라운드 실행을 통해, 여러 프로세스로 분할하여 성능 향상)

    $ vi find_opened_port.sh
    #!/bin/bash 
    for i in {1..65536} 
    do 
        tcping 192.168.0.1 $i & # 조사하고 싶은 IP 
    done 
    
    wait
  4. 셸 스크립트 실행

    $ chmod +x find_opened_port.sh 
    $ ./find_opened_port.sh | grep open

백그라운드 실행 속도 체감 영상

tcping 백그라운드 속도 차이.mp4
11.89MB

Java 2022. 12. 10. 11:12

OpenJDK 아카이브 링크

https://jdk.java.net/archive/

 

 

Windows 2022. 11. 14. 09:15

Windows Citrix Workspace 화면이 창 밖에 있을 때

  • 굉장히 뜬금없게도 특정 citrix workspace만 화면 밖으로 창이 나가서 안 보이는 상태가 되었다.
  • 심지어 키보드를 바로 리디렉션하도록 레지스트리를 설정해두어, 창을 키보드로 제어할 수 없었다.
  • 작업표시줄에서 우클릭 후 최대화를 누르면 창이 잘 살아있는 것을 확인할 수 있었는데, 그 상태로 최대화를 해제하면 또 사라졌다.

해결

  • 작업표시줄에서 우클릭 후 이동을 누르고, 방향키로 움직여서 꺼내오면 된다..

 

Java 2022. 11. 11. 01:26

Java의 정석 13장 리뷰

  • 쓰레드를 구현할 때는 run() 메서드를, 실행할 때는 start() 메서드를 호출한다. (p.726)
    • 쓰레드의 호출 스택을 별도로 생성하기 위해서이다.
  • 쓰레드 그룹(thread group) (p.741)
    • 보안 상 이유로 도입된, 쓰레드를 그룹으로 관리하는 클래스이다.
      • 자신이 속한 쓰레드 그룹이나 하위 쓰레드 그룹은 변경할 수 있지만, 다른 쓰레드 그룹의 쓰레드를 변경할 수는 없다.
    • 모든 쓰레드는 반드시 쓰레드 그룹에 포함되어 있어야 하며, 기본적으로는 부모 쓰레드와 같은 쓰레드 그룹에 속한다.
    • JVM은 기본적으로 system과 main 쓰레드 그룹을 생성한다.
    • 다음과 같이 참조 변수 없이 쓰레드를 생성하여 바로 실행시켜도, 이 쓰레드의 참조가 ThreadGroup에 저장되어 있기 때문에 GC 대상이 되지 않는다.
      public static void main(String[] args) throws Exception {
      		ThreadGroup grp1 = new ThreadGroup("Group1");
      		
      		new Thread(grp1, () -> {
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {}
          }, "th1").start();
      }
  • 관련 메서드
    • getAllStackTraces()
      • 작업이 완료되지 않은 모든 쓰레드의 호출스택을 출력할 수 있다.
    • Thread.sleep()
      • sleep() 메서드는 static으로 선언되어 항상 현재 실행 중인 쓰레드에 대해 작동하기 때문에, 다른 쓰레드 인스턴스 메서드를 호출하는 코드(th1.sleep(1000) 등)를 작성해도 해당 쓰레드가 아닌 현재 쓰레드가 WAITING 상태로 들어간다.
    • isInterrupted()
      • interrupted() 메서드와 달리, isInterrupted() 메서드는 쓰레드의 interrupted 상태를 false로 초기화하지 않는다.

       

       

    • suspend(), resume(), stop() (p.755)
      • suspend() 메서드는 sleep() 메서드처럼 쓰레드를 멈추게 하고, resume() 메서드를 통해 실행대기 상태로 돌릴 수 있다.
      • stop() 메서드는 호출 즉시 쓰레드를 종료시킨다.
      • 위의 메서드들은 데드락을 일으키기 쉽게 작성되어 있어서, deprecated 되었다.
    • yield() (p.760)
      • 쓰레드의 남은 할당 시간을 포기하고 다시 실행대기 상태로 돌아가는 메서드이다.
      • while 무한루프 + Thread.sleep() + Thread.yield() 조합으로 애플리케이션의 응답 속도를 높일 수 있다. (busy-waiting 방지)
        • (참고) suspend()stop() 메서드 호출 시에 interrupt() 메서드를 사용하면 Waiting 상태에서 바로 깨어나서 정지시키는 기법으로도 응답 속도를 높일 수 있다.
  • InterruptedException (p.754)
    • Thread.sleep() 메서드 실행 중(Waiting 상태) interrupt 신호를 받으면, 해당 메서드에서 InterruptedException이 발생하고 interrupted 상태는 false로 자동 초기화된다. 따라서 해당 코드 바깥의 try ~ catch 문까지 interrupt 신호가 전달되지 않는다.
  • Concurrency
    • synchronized 블럭
      • 블럭이나 메서드에 synchronized 키워드를 붙이면, 내부 코드에 접근 시 자동으로 임계 영역이 설정된다.
        synchronized(객체의 참조변수) {
            // Critical Section
        }
    • wait(), notify()
      • synchronized 블럭은 특정 쓰레드가 객체의 락을 가진 상태로 오랜 시간 있을 수 있기 때문에, 이를 보완하고자 나온 메서드가 위의 두 가지이다.
      • 두 메서드는 Object 클래스에 정의되어 있다.
      • notifyAll() : 기다리는 모든 쓰레드에게 통보한다. 단, lock을 얻을 수 있는 건 하나의 쓰레드 뿐이다.
    • Lock
      • java.util.concurrent.locks 패키지(JDK 1.5 이상)의 lock 클래스들을 이용할 수도 있다.
      • ReentrantLock
        • 가장 일반적인 Lock이다.
        • 생성자에 ReentrantLock(boolean fair) 와 같이 fait 변수를 줄 수 있고, 이 값이 true면 가장 오래 기다린 쓰레드가 Lock을 획득하도록 한다. 하지만 이 과정에서 성능이 떨어지며, 대부분의 경우 공정함보다는 성능을 선택한다.
        • tryLock() 메서드는, 다른 쓰레드에 의해 Lock이 걸려있으면 기다리지 않거나 인자로 받은 시간만큼만 기다리고 Lock을 얻지 못하면 false를 반환한다. 당연히 얻으면 true를 반환한다.
      • ReentrantReadWriteLock
        • 읽기 Lock이 걸려있을 경우, 다른 쓰레드가 읽기 Lock을 중복해서 걸고 데이터를 읽을 수 있다. 하지만 읽기 Lock과 쓰기 Lock을 동시에 걸 수는 없다.
      • StampedLock
        • 읽기, 쓰기 Lock 외에 낙관적 읽기 Lock(optimistic reading lock)을 추가한 것이다. 읽기 Lock이 풀리는 것을, 쓰기 Lock이 기다리는 걸 방지하려고 낙관적 읽기 Lock을 만든 것이다.
        • 낙관적 읽기 Lock은 쓰기 Lock에 의해 바로 풀린다.
        • 즉, 쓰기와 읽기 충돌 시 쓰기가 끝난 후에 읽기 Lock을 건다.

       

    • Condition
      • 쓰레드가 원하는 Lock의 종류를 구분하기 위한 waiting pool이다.
      • Object 클래스의 wait(), notify() 메서드 대신, Condition의 await(), signal() 메서드를 사용하면 된다.
  • volatile (p.786)
    • 코어에서 변수의 값을 읽을 때, 캐시가 아닌 메모리에서 읽어오도록 강제하는 키워드로 사용한다.
      • C, C++의 volatile 키워드와 문맥이 다른 것 같다. (C 계열에서는 최적화 방지 키워드로 사용)
  • fork & join (p.788)
    • JDK 1.7부터 추가된, 하나의 작업을 작은 단위로 나눠서 여러 쓰레드가 동시에 처리하도록 하는 기법이다.
    • RecursiveAction : 반환 값이 없는 작업 구현 시 사용
    • RecursiveTask : 반환 값이 있는 작업 구현 시 사용
Linux 2022. 11. 8. 14:29

Solaris 10 ps command 전체 출력

  • Solaris 10 (SunOS 5.1) 에서 겪은 ps 명령어에 관련된 메모이다.
  • ps 명령어를 통해 CMD를 보고 싶을 경우, 터미널의 글자 수 제한 설정 때문에 상세 내용을 전부 볼 수 없다.
  • OS 종류 및 버전에 따라 ps 지원 옵션이 다르기 때문에, 흔히 사용하는 -x , -ww 옵션을 사용할 수 없었다.

해결

  • 완벽한 해결책은 아니지만, CMD를 봐야 하는 상황에서 다음 명령어를 통해 ps 컬럼들을 볼 수 있다.
$ pargs <PID>

 

참고

 

'Linux' 카테고리의 다른 글

우분투 oh-my-zsh 설치  (0) 2021.04.23
VSCode Remote-SSH 플러그인 에러  (0) 2021.04.02
Vim  (0) 2021.03.08
Java 2022. 11. 7. 02:08

백기선 스프링 프레임워크 핵심 기술 완강 후기

후기
  • Spring Framework의 Core 부분만 간략하게 학습한 것인데도 상당히 방대하다고 느꼈다.
  • Spring Boot를 사용하면 상당히 편리해 보이는 부분이 많아서, 요즘 추세에 따라 반드시 알아야 할 것 같다.
  • 토비의 스프링 3에 많은 정보가 있는 듯 하다. 백기선 스프링 커리큘럼 완강 이후 심화 학습용으로 보면 좋을 것 같다.
  • 리액트나 안드로이드의 라이프사이클을 파악해야 쉽게 프로그래밍할 수 있는 것처럼, 스프링 Bean의 라이프사이클을 아는 것이 중요한 것 같다.

 

스프링
  • 등장 시기 : 2003년
  • 스프링 5부터는 서블릿 기반이 아닌 서버 애플리케이션도 개발할 수 있게 되었다. (WebFlux 지원)
디자인 철학
  • 특정 기술을 강요하지 않는다.
  • 다양한 관점을 지향한다.
  • 하위 호환성을 지킨다.
  • API를 신중하게 설계한다.
  • 높은 수준의 코드를 지향한다.

 

스프링 프레임워크 핵심 기술
  • Spring IoC Container
    • IoC Container
      • 객체가 사용하는 의존 객체를 직접 만들어 사용하는 게 아니라, 주입 받아 사용하는 방법을 뜻한다.
      • DI(Dependency Injection, 의존성 주입)이라고도 한다.
    • Spring Bean
      • 스프링 IoC 컨테이너가 관리하는 객체이다.
      • 사용 시 장점
        • 의존성 관리가 수월하다.
        • 스코프를 쉽게 지정할 수 있다.
          • 싱글톤, 프로토타입, 쓰레드 등
        • 라이프사이클 인터페이스가 존재하여, 필요 시 해당 메서드를 Override하여 사용할 수 있다.
      • 참고) Java Bean
        • 스프링 빈이 아닌 자바 빈 규약도 존재한다.
        • 자바 빈 특징
          • 기본 패키지 외 특정 패키지에 속한다.
          • 매개변수가 없는 기본 생성자가 존재한다.
          • 멤버변수의 접근제어자는 private이다.
          • 접근제어자가 public인 getter, setter가 존재한다.
          • (Optional) 직렬화가 가능하다.
    • 스프링 빈 설정 방법
      • 스프링 빈 직접 설정 (스프링 빈에 대한 정의)
        • 이름, 클래스, 스코프, Constructor, Setter 등
      • Component Scan
        • 특정 패키지 이하의 모든 클래스를 순회하여 @Component 애노테이션이 붙은 클래스를 스프링 빈으로 등록한다.
        • 설정 방법
          • context:component-scan : XML
          • @ComponentScan : Java
    • @Autowired
      • 의존 객체의 타입을 통해 해당 스프링 빈을 찾아서 주입하는 애노테이션이다.
      • 옵션
        • required (기본 값 = true) : 스프링 빈에서 해당 타입을 못 찾으면 애플리케이션 구동에 실패한다.
      • 사용할 수 있는 위치
        • 생성자 주입 (스프링 4.3 부터 생략 가능)
        • 수정자(Setter) 주입
        • 필드 주입
      • 같은 타입의 빈이 여러 개 인 경우 (상속, 인터페이스 구현 등)
        • 기본적으로는 변수명을 PascalCase로 변환한 타입의 스프링 빈을 주입한다.
        • 우선적으로 주입하고 싶은 스프링 빈에 @Primary 애노테이션을 붙이면 우선적용된다. (권장)
        • @Qualifier(빈이름) 애노테이션을 통해서 개별적으로 적용할 수도 있다.
    • @Component, @ComponentScan
      • @Component : 스캔 대상이 될 빈을 지정한다.
        • @Component 애노테이션을 적용한 애노테이션들
          • @Repository
          • @Service
          • @Controller
          • @Configuration

           

      • @ComponentScan : 스캔할 패키지 위치와 필터링 할 애노테이션에 대한 정보를 제공한다.
      • 스프링 빈을 직접 등록하는 방법
        public static void main(String[] args) {
            new SpringApplicationBuilder()
                .sources(Demospring51Application.class)
                .initializers((ApplicationContextInitializer<GenericApplicationContext>) applicationContext -> {
                    applicationContext.registerBean(MyBean.class);
                })
                .run(args);
        }
    • 빈 스코프
      • 스코프 종류
        • 싱글톤
        • 프로토타입
          • Request
          • Session
          • WebSocket
          • 기타 등등
      • 싱글톤 빈이 프로토타입 빈을 참조할 경우
        • 프로토타입 빈은 사용할 때마다 다른 인스턴스를 사용해야 하는데, 싱글톤 빈은 반드시 하나만 존재하므로 꺼내 사용할 때 프로토타입 빈이 수정되지 않는 문제가 발생한다.
        • 이를 해결하기 위해 Proxy 패턴을 사용한다.
          • ScopedProxy : 프로토타입 빈 클래스 @Scope 애노테이션에 proxyMode=ScopedProxyMode.TARGET_CLASS 속성을 주면 CGLib 다이나믹 프록시가 적용되어 매번 인스턴스가 달라진다.
            • TARGET_CLASS 로 주는 이유 : JDK 다이나믹 프록시는 Interface로만 만들 수 있는데, Class를 대상으로 하여 서드파티 다이나믹 프록시 라이브러리인 CGLib를 사용하도록 지정함
          • ObjectProvider : 프로토타입 빈을 참조하는 코드를 ObjectProvider로 감싸서 프록시 패턴을 적용할 수도 있다. (비권장 - 소스코드에 스프링코드가 들어가기 때문)
    • Environment
      • ApplicationContext extends EnvironmentCapable : EnvironmentCapable 인터페이스 기반으로 환경 설정을 제공한다.
      • 프로파일
        • 개발 환경과 배포 환경에서 서로 다른 빈을 사용하고 싶을 때 적용하는 프로파일을 의미한다.ex. 배포 시에만 사용할 모니터링 빈은 테스트 환경에서 필요 없으므로 등록하지 않고싶은 경우
        • 프로파일 정의 방법 : @Profile("프로파일명") 애노테이션을 클래스나 메소드에 붙인다.
          • 프로파일 표현식 : !, &, | 등 논리 연산자를 조합하여 다양하게 활동할 수 있다.
        • 프로파일 설정 방법 : Java VM 옵션으로 다음 값을 준다. -Dspring.profiles.active="프로파일명"
          • 혹은 IntelliJ 설정에서 Active Profile 속성으로 값을 주면 되는데 아마 Ultimate 버전만 뜨는 듯 하다.

         

      • 프로퍼티
        • VM 옵션이나 프로퍼티 파일에서 속성을 불러와 사용할 수 있다.
        • @PropertySource : 프로퍼티 파일에서 속성을 불러올 수 있다.
        • 우선 순위가 높은 프로퍼티를 적용하여 제공한다.
        • 스프링 부트 기본 프로퍼티 소스 : application.properties
    • MessageSource
      • ApplicationContext extends MessageSource : 국제화 기능(다국어 지원, i18n)을 제공하는 인터페이스이다.
      • 스프링 부트 사용 시 기본적으로 message.properties 등 파일을 사용할 수 있다.
        • 다국어 메시지 프로퍼티 파일 네이밍 규칙은 해당 언어를 언더바로 이으면 된다.
          • messages_ko_kr.properties
      • ReloadableResourceBundleMessageSource 객체를 통해 프로퍼티 파일이 실시간으로 반영되도록 할 수 있다. (Build 시 적용된다.)
    • ApplicationEventPublisher
      • ApplicationContext extends ApplicationEventPublisher : 이벤트 프로그래밍에 필요한 인터페이스를 제공한다. (옵저버 패턴)
      • Event
        • ApplicationEvent 를 상속받는 클래스를 사용한다. (스프링 4.2부터는 상속 안 해도 사용 가능)
      • 이벤트 발생시키기 : ApplicationEventPublisher.publishEvent();
      • 이벤트 핸들링 : ApplicationListener<이벤트> 를 구현하여 빈으로 등록한다.
        • 스프링 4.2부터는 @EventListener 애노테이션을 스프링 빈 메소드에 붙여서 사용할 수 있다.
        • @Order : 동일 이벤트에 대한 핸들링의 순서를 정할 수 있다.
        • @Async : 비동기로 실행한다. (기본 핸들링은 동기적으로 처리된다.)
      • 스프링 제공 기본 이벤트
        • ContextRefreshedEvent : ApplicationContext 초기화 or 리프레시 시 발생한다.
        • ContextStartedEvent : ApplicationContext start() 를 통해 라이프사이클 빈이 시작 신호를 받은 시점에 발생한다.
        • ContextStoppedEvent : ApplicationContext stop() 을 통해 라이프사이클 빈이 정지 신호를 받은 시점에 발생한다.
        • ContextClosedEvent : ApplicationContext close()를 통해 싱글톤 빈이 소멸되는 시점에 발생한다.
        • RequestHandledEvent : HTTP 요청을 처리했을 때 발생한다.

       

    • ResourceLoader
      • ApplicationContext extends ResourceLoader : 리소스를 읽어오는 기능을 제공한다.
      • 리소스 읽어오는 메서드 : getResource(String location)
      • 리소스를 어떤 방식으로 읽어올 수 있는가? (location 종류)
        • 파일 시스템
        • classpath
        • URL
        • 상대경로, 절대경로
  • 스프링 추상화
    • Resource 추상화
      • org.springframework.core.io.Resource : 스프링 내부에서 많이 사용하는, java.net.URL 을 추상화 한 인터페이스이다.
      • 추상화 이유
        • classpath 기준 리소스 읽어오는 기능 부재
        • ServletContext 기준 상대 경로로 읽어오는 기능 부재
      • 주요 메서드
        • getInputStream()
        • exists()
        • isOpen()
        • getDescription() : 전체 경로 포함한 파일 이름 또는 실제 URL
      • 주요 구현체
        • UrlResource : http, https, ftp, file, jar 프로토콜 기본 지원
        • ClassPathResource : classpath: 접두어 지원
        • FileSystemResource
        • ServletContextResource : 웹 애플리케이션 루트에서 상대 경로로 리소스를 찾는다.
      • 리소스 읽어오기
        • 리소스의 타입은 getResource(String location)location 문자열과 ApplicationContext 타입에 따라 결정된다.
          • ClassPathXmlApplicationContextClassPathResource
          • FileSystemXmlApplicationContextFileSystemResource
          • WebApplicationContextServletContextResource
        • ApplicationContext 타입에 상관없이 리소스 타입을 강제하기 위해서 java.net.URL 접두어 중 하나를 사용할 수 있다. (권장)
          • classpath:ClassPathResource
          • file://FileSystemResource
            • 루트 경로부터 시작하려면 다소 이상하게 보이지만 file:///something/path 이런 식으로 작성해야 한다.
    • Validation 추상화
      • 모든 계층(웹, 서비스, 데이터)에서 사용해도 된다. (어떠한 계층과도 관계가 없다.)
      • 데이터 바인딩 시 같이 사용되기도 한다.
      • 메서드 오버라이딩
        • supports(Class clazz) : 특정 타입의 객체를 검증할 때 사용할 것인지 결정한다.
        • validate(Object obj, Errors e) : 실제 검증 로직을 이 안에서 구현한다.
          • 구현 시 ValidationUtils 를 사용한다.
      • 스프링 부트 2.0.5 이상 버전 사용 시
        • LocalValidatorFactoryBean 을 스프링 빈으로 자동 등록해준다.
        • Default message도 위의 클래스에서 제공한다.

       

    • 데이터 바인딩 추상화
      • 사용자 입력 값(문자열)을 애플리케이션 도메인 모델(객체)에 동적으로 변환하여 입력하는 기능이다.
      • PropertyEditor : 스프링 3.0 이전까지 DataBinder 가 바인딩 작업에 사용하던 인터페이스이다.
        • 상태 정보를 저장하기 때문에 thread-safe하지 않다.
        • Object ~ String 간 변환만 지원하여, 사용 범위가 다소 제한적이다.
        • PropertyEditorSupportgetAsText(), setAsText 메서드를 오버라이딩하여 사용한다.
      • ConversionService : DataBinder 대신에 타입 변환 작업에 사용하는 인터페이스이며, thread-safe 하다.
        • addFormatters() 메서드를 통해 ConverterFormatter를 등록할 수 있다.
          • DefaultFormattingConversionServiceFormatterRegistryConverterRegistry 상속 구조
        • 스프링 MVC, SpEL 등에서 사용한다.
        • Converter : 일반적인 S(source) → T(target) 타입 변환기
          • 상태 정보를 저장하지 않아 thread-safe하다.
          • ConverterRegistry 에 등록해서 사용한다.
        • Formatter : PropertyEditor 를 대체한다.
          • Object ~ String 변환에 사용한다.
          • 문자열을 Locale에 따라 다국화 할 수 있다.
          • FormatterRegistry 에 등록해서 사용한다.
        • 스프링 부트에서 웹 애플리케이션인 경우, public classWebConversionService extendsDefaultFormattingConversionService 를 스프링 빈으로 등록하여, FormatterConverter 스프링 빈을 찾아 자동으로 등록해준다.

       

  • SpEL (Spring Expression Language)
    • Unified EL 과 비슷하나, 메소드 호출을 지원하며, 문자열 템플릿 기능도 제공한다.
    • 스프링 3.0 부터 지원하는 표현식이다.
    • 문법
      • #{”표현식”}
      • ${"프로퍼티"}
      • 표현식 안에 프로퍼티 사용 가능 (#{${my.data} + 1})
    • 주로 사용하는 곳
      • @Value, @ConditionalOnExpression 애노테이션
      • 스프링 시큐리티
      • 스프링 데이터 : @Query 애노테이션
      • Thymeleaf
  • 스프링 AOP (Aspect-Oriented Programming)
    • AOP : 흩어진 Aspect를 모듈화 하는 프로그래밍 기법이다.
      • Aspect : 관심사를 모듈화 한 것. 즉 공통적으로 사용되는 코드 모듈을 의미한다.
      • Advice : Aspect에서 수행할 실질적 작업
      • Target : Aspect의 적용 대상
      • Join Point : Advice가 적용될 수 있는 지점
      • Pointcut : Advice가 적용될 Join Point 지점을 의미한다. (Join Point의 한 부분)
    • Java AOP 구현체
      • AspectJ
      • Spring AOP
    • 스프링 AOP 특징
      • 프록시 기반의 AOP 구현체이다.
        • 프록시 패턴 사용 이유 : 기존 코드의 변경 없이 접근 제어 또는 부가 기능을 추가하기 용이하다.
      • 스프링 빈에만 AOP 적용 가능하다.
      • 동적 프록시
        • Java 제공 프록시 : 인터페이스 기반의 프록시를 생성할 수 있다.
        • CGlib : 클래스 기반의 프록시 생성도 지원한다.
      • 스프링 IoC : AbstractAutoProxyCreator implements BeanPostProcessor 를 통해 기존 스프링 빈을 대체하는 동적 프록시 빈을 생성하여 등록시킨다.

         

      • 프록시 클래스를 작성하여 구현할 수 있으나, 애노테이션 기반의 스프링 AOP를 통해 매번 프록시 클래스를 작성해야 하는 번거로움을 줄일 수 있다.
    • @AOP
      • 스프링 부트에서 제공하는 AOP 애노테이션이다.
      • Aspect 정의 : @Aspect
        • 빈으로 등록해야 하므로 @Component 도 추가해야 한다.
      • Advice 정의
        • 다음 애노테이션을 통해 Advice가 적용될 범위를 설정할 수 있다.
          • @Around : ProceedingJoinPoint 매개변수를 받는 함수를 통해 Advice를 구현한다. 원래의 메서드가 실행되기 전후로 Advice를 설정할 수 있는 장점이 있다.
          • @Before
          • @AfterReturning
          • @AfterThrowing
      • Pointcut 정의 : @Pointcut
        • Pointcut Designator (표현식)
          • execution
          • @annotation
          • bean
        • 포인트컷 조합식
          • &&, ||, !

     

  • Null-safety
    • 스프링 프레임워크 5에 추가된, 컴파일 시점에 최대한 NullPointerException을 방지하기 위한 Null 관련 애노테이션이다.
    • 종류
      • @NonNull
      • @Nullable
      • @NonNullApi : 패키지 레벨
      • @NonNullFields : 패키지 레벨
TODO
  • 자바 클래스 로딩 복습

 

 

'Java' 카테고리의 다른 글

JIT 컴파일  (0) 2023.01.14
OpenJDK 아카이브 링크  (0) 2022.12.10
Java의 정석 13장 리뷰  (1) 2022.11.11
Java 이클립스 The project description file (.project) for ~ is missing 에러  (0) 2021.12.13
Review 2022. 11. 1. 20:36

백기선 스프링 프레임워크 입문 강의 수강 후기

  • 스프링의 철학을 맛볼 수 있었다.
  • 스프링에 익숙해지기 좋은 예시인 Petclinic(https://github.com/spring-projects/spring-petclinic) 프로젝트를 알게 되어 좋았다.
  • 18백기선의 매력을 알 수 있었다.. 불꽃놀이를 보러가고 싶어하는 성격 확인…
    • 인프런 배속 기능 단축키는 < , > 이며, 스킵(방향키)보다는 배속 기능을 활용하는 게 내용을 놓치는 일 없이 마음대로 볼 수 있어서 좋다.

IoC (Inversion of Control)

  • 사용하는 메서드에서 객체 인스턴스를 생성하는 게 아니라, 누군가 알아서 생성하여 제공한다고 생각하고 사용하는 방식이다. (실제로 IoC 컨테이너가 제공)
  • 테스트 코드 작성에도 유리하다.

IoC 컨테이너

  • 대표적으로 ApplicationContext (BeanFactory)
  • 스프링 Bean을 생성하여 제공한다.

Bean

  • IoC 컨테이너가 관리하는 객체이다.
  • Component Scanning으로 자동 등록하는 방식과, 직접 XML이나 자바 설정파일에 등록하는 방법이 존재한다.
    • Component Scanning은 @ComponentScan 애노테이션을 통해 해당 애노테이션이 있는 디렉토리부터 하위 경로를 모두 스캔하여 @Component 애노테이션이 붙은 항목을 Bean으로 등록하는 방식이다.
      • @ComponentScan 애노테이션 매개변수를 통해 하위 디렉토리가 아닌 외부 경로의 Element도 Bean으로 등록할 수 있다고 하는데, 굳이 사용하지 않아도 될 것 같다.
    • XML이나 자바 설정파일에 등록하는 방법은 @Configuration 이 붙은 클래스에 Bean을 명시하는 방식인데, 사실 잘 안 쓸 것 같아 일단 잊었다.
  • 사용법
    • @Autowired , @Inject 애노테이션으로 사용할 수 있다.
      • 해당 애노테이션들은 생성자, 필드, Setter에 붙일 수 있다. Setter가 있다면 필드에 직접 붙이는 것 보다는 Setter에 붙이는 게 낫고, 없다면 굳이 Setter를 만들지 않고 필드에 붙이는 게 합리적일 것이라고 한다. 내 생각도 그렇다.
      • 이것이 DI다.
    • ApplicationContext.getBean(”빈이름”) 으로도 직접 꺼낼 수 있다.
      • IDE 추적을 위해 ApplicationContext.getBean(Something.class) 형식으로 클래스 명을 꺼내서 쓰는 듯..?

DI (Dependency Injection)

  • Bean을 필요한 곳에 넣어주는 것..
  • 장점 순위 : 생성자 주입 > Setter 주입 > 필드 주입

AOP (Aspect Oriented Programming)

  • 여러 메서드의 공통 부분 처리를 담당하는 코드를 모아서 중복을 없애고 관리를 쉽게 한다.
  • 직접 구현하려면 @Aspect , @Around 애노테이션을 통해 특정 애노테이션이 붙은 Element에 대해 동작을 설정할 수 있다. (ProceedingJoinPoint 객체 사용.. 얘도 DI로 받아옴)

PSA (Portable Service Abstraction)

  • PSA라는 잘 만든 인터페이스를 기반으로 코드를 작성하면, 이 인터페이스를 구체화한 기술이 변경되어도 내 코드는 그대로 사용할 수 있다.
  • 예를 들어 스프링 트랜잭션, 스프링 캐시, 스프링 웹 MVC 등에서 PSA에 해당하는 애노테이션(@Transactional, @Cacheable, @Controller 등)을 사용하면, 데이터 소스나 캐시 구현체, 서블릿이나 Reactive 등의 구현 기술이 변경되어도 내 코드를 그대로 사용할 수 있다.
Utility 2022. 10. 10. 18:57

IntelliJ (PyCharm) Jinja2 html 파일 매핑

- python template language를 Jinja2 로 설정하였는데도, html 파일의 {{ }}, {% %} 등 Jinja 문법이 나오면 expression expected 라며 인텔리제이가 화를 냈다.

- 다음 경로에서 *.html 파일을 Jinja 2 템플릿에 추가하면 된다. (기존 HTML 템플릿에서는 삭제 - 추가 시 삭제할 건지 물어봄)

  - File | Settings | Editor | File Types, Jinja 2 Template


참고

https://stackoverflow.com/questions/53179239/pycharm-python-template-language-is-stuck-on-jinja2

 

MacOS 2022. 10. 9. 14:53

맥북 클램쉘 모드로 외부 모니터 연결 시 알림이 울리지 않는 현상

썬더볼트 독을 사용한 이후부터, 카카오톡 알림이 울리지 않는 현상이 생겼다. 결과적으로는 하기 4번을 통해 해결하였다.

 

해결 방법

1. 어플리케이션 내 알림 설정 확인

  - 카카오톡의 경우, 전체적인 알림을 끄는 버튼과 세부 설정에서 소리 알림 등을 설정할 수 있다.


2. 시스템 설정에서 알림 허용 여부 확인

- Command + Space 후 알림 및 집중 모드로 들어간다.

- 특정 시점 이후 MacOS 부터는 카카오톡 초기 설치 시 알림 허용이 비활성화 상태라는 것 같다.


3. 방해금지모드 확인

- 집중 모드 탭에서, 방해금지모드가 활성화되어 있는지 여부를 확인한다.

 


4. 알림 허용 설정 중 "디스플레이를 미러링하거나 공유할 때" 체크 여부 확인

- 이 부분이 문제였는데, 해당 항목을 체크해야 클램쉘 모드에서도 외부 모니터 사용 시 정상적으로 알림이 뜬다.

'MacOS' 카테고리의 다른 글

MacOS VoiceOver 단축키 비활성화  (0) 2023.01.04
MacOS hosts file 경로  (0) 2023.01.04
macOS 특정 IP 열린 포트번호 확인  (0) 2023.01.01
VSCode remote-ssh 플러그인 localhost port forwarding  (0) 2021.11.11
MacOS 자잘한 설정들  (0) 2021.04.18
Utility/VSCode 2022. 10. 2. 22:36

VSCode workspace에서 특정 패턴 제외

- Setting -> exclude 검색 후 패턴 추가

Windows 2022. 6. 20. 19:54

윈도우 그림판 경로

윈도우 10 이하 : C:\Windows\System32\mspaint.exe

윈도우11 : %USERPROFILE%\AppData\Local\Microsoft\WindowsApps\mspaint.exe

Utility 2022. 6. 15. 10:41

네이버 웨일 브라우저 다른 기기 로그아웃

https://myactivity.whale.naver.com/devices

Windows 2021. 12. 17. 01:27

Onedrive Personal Vault (개인 중요 보관소) 비활성화

  1. 온라인 Onedrive 접속

  2. 설정 -> 옵션 에 들어간 후 개인 중요 보관소 사용 안함을 활성화


Java 2021. 12. 13. 19:14

Java 이클립스 The project description file (.project) for ~ is missing 에러

workspace를 구성하고나서 리포지토리를 옮겼더니 이클립스를 켜서 Navigator를 볼 때 위의 에러가 발생했다.

.metadata\.plugins\org.eclipse.core.resources\.projects\프로젝트명\.location 의 경로와 실제 경로가 맞지 않으면 발생하는 것 같다.

.metadata\.plugins\org.eclipse.core.resources\.projects 폴더를 지우고 다시 이클립스를 켰더니 해결됐다.

참고

'Java' 카테고리의 다른 글

JIT 컴파일  (0) 2023.01.14
OpenJDK 아카이브 링크  (0) 2022.12.10
Java의 정석 13장 리뷰  (1) 2022.11.11
백기선 스프링 프레임워크 핵심 기술 완강 후기  (0) 2022.11.07
MacOS 2021. 11. 11. 22:45

VSCode remote-ssh 플러그인 localhost port forwarding

문제점 발견

remote-ssh를 통해 라즈베리파이에서 웹서버를 열면, localhost:8000 주소가 라즈베리파이로 자동 연결되는 현상이 발생했다.

뭐가 잘못된 건지 몰랐었는데, 로컬에서 서버를 하나 더 열면서 localhost에서 8000번 포트가 사용 중인 것을 발견했다.

  $ python manage.py runserver
  Watching for file changes with StatReloader
  Performing system checks...

  System check identified no issues (0 silenced).
  November 11, 2021 - 06:52:53
  Django version 2.2.5, using settings 'mysite.settings'
  Starting development server at http://127.0.0.1:8000/
  Quit the server with CONTROL-C.
  Error: That port is already in use.

해당 포트를 사용하는 프로세스 확인

netstat

netstat 명령어로 특정 포트를 사용 중인 프로세스의 아이디PID를 찾을 수 있다.

  $ netstat -anv | head -2 | tail -1; netstat -anv | grep 8000
  Proto Recv-Q Send-Q  Local Address          Foreign Address        (state)     rhiwat shiwat    pid   epid  state    options
  tcp4       0      0  127.0.0.1.8000         *.*                    LISTEN      131072 131072  56783      0 0x0100 0x00000106

ps

PID가 56783인 프로세스의 이름을 찾아보자

  $ ps -f 56783
  UID   PID  PPID   C STIME   TTY           TIME CMD
  501 56783 56754   0 화04PM ??         1:58.66 /Applications/Visual Studio Code.app/Contents/Frameworks/Code Helper (Renderer).app/Contents/MacOS/Code Helper ...이하생략

VSCode에서 포트포워딩 비활성화

remote-ssh를 사용하는 VSCode 창에서 F1 이나 Command + Shift + P 를 누르고 Stop Forwaring Port 를 찾아서 포트를 비활성화하면 끝


참고

Windows 2021. 10. 31. 00:36

MS 워드 영어 한글 자동 변환 끄기

마이크로소프트 word에서 영어를 자동으로 변환해주는 기능이 있는데, 의도와 다르게 변환되는 경우가 종종 있어서 그냥 끄는게 낫다고 판단하였다.

순서

  • 워드 왼쪽 위의 파일을 클릭하고 옵션 을 선택한다.

  • 언어 교정 탭의 자동 고침 옵션 을 클릭한다.

  • 한/영 자동 고침 체크를 해제하고 확인을 클릭하여 저장한다.

Linux/Linux Structure 2021. 9. 26. 03:07

실습과 그림으로 배우는 리눅스 구조 학습 내용

커버 이미지

실습과 그림으로 배우는 리눅스 구조 - 타케우치 사토루


Contents

Chapter 1. 컴퓨터 시스템의 개요

Chapter 2. 사용자 모드로 구현되는 기능

Chapter 3. 프로세스 관리

Chapter 4. 프로세스 스케줄러

Chapter 5. 메모리 관리

Chapter 6. 메모리 계층

Chapter 7. 파일시스템

Chapter 8. 저장 장치


실습 환경

Surface Pro 7 - Microsoft

  • CPU : 인텔® 코어™ i5-1035G4 프로세서 (6M 캐시, 최대 3.70GHz)

    주요 정보
    제품 컬렉션 10세대 인텔® 코어™ i5 프로세서
    코드 이름 이전 제품명 Ice Lake
    수직 분야 Mobile
    프로세서 번호 i5-1035G4
    상태 Launched
    출시일 Q3'19
    리소그래피 10 nm
    사용 조건 PC/Client/Tablet
    고객 권장가격 $309.00
    CPU 사양
    코어 수 4
    스레드 수 8
    프로세서 기본 주파수 1.10 GHz
    최대 터보 주파수 3.70 GHz
    캐시 6 MB Intel® Smart Cache
    버스 속도 4 GT/s
    TDP 15 W
    구성 가능한 TDP-up 주파수 1.50 GHz
    구성 가능한 TDP-up 25 W
    구성 가능한 TDP-down 주파수 800 MHz
    구성 가능한 TDP-down 12 W
    보조 정보
    사용 가능한 임베디드 옵션 아니요
    데이터시트 지금 보기
    메모리 사양
    최대 메모리 크기(메모리 유형에 따라 다름) 64 GB
    메모리 유형 DDR4-3200, LPDDR4-3733
    최대 메모리 채널 수 2
    최대 메모리 대역폭 58.3 GB/s
    ECC 메모리 지원 ‡ 아니요
    프로세서 그래픽
    프로세서 그래픽 ‡ 인텔® Iris® Plus 그래픽
    그래픽 기본 주파수 300 MHz
    그래픽 최대 동적 주파수 1.05 GHz
    그래픽 출력 eDP/DP/HDMI
    최대 해상도(HDMI 1.4)‡ 4096 x 2304@60Hz
    최대 해상도(DP)‡ 5120 x 3200@60Hz
    최대 해상도(eDP - 통합 평판) 5120 x 3200@60Hz
    DirectX* 지원 12
    OpenGL* 지원 4.5
    인텔® 퀵 싱크 비디오
    지원되는 디스플레이 수 ‡ 3
    장치 ID 0x8A5A
    확장 옵션
    PCI Express 개정판 3
    패키지 사양
    소켓 지원 FCBGA1526
    최대 CPU 구성 1
    TJUNCTION 100°C
    패키지 크기 50mm x 25mm
    고급 기술
    인텔® 딥 러닝 부스트
    인텔® Optane™ 메모리 지원 ‡
    Intel® Speed Shift Technology
    인텔® Thermal Velocity Boost 아니요
    인텔® 터보 부스트 기술 ‡ 2
    인텔® v프로™ 플랫폼 적격성 ‡ 아니요
    인텔® 하이퍼 스레딩 기술 ‡
    인텔® 가상화 기술(VT-x) ‡
    직접 I/O를 위한 인텔® 가상화 기술(VT-d) ‡
    인텔® VT-x with Extended Page Tables(EPT) ‡
    인텔® TSX-NI 아니요
    인텔® 64 ‡
    명령 세트 64-bit
    명령 세트 확장 Intel® SSE4.1, Intel® SSE4.2, Intel® AVX2, Intel® AVX-512
    유휴 상태
    열 모니터링 기술
    인텔® 안정화 이미지 플랫폼 프로그램(SIPP) 아니요
    인텔® Adaptix™ 기술
    보안 및 신뢰성
    Intel® AES New Instructions
    보안 키
    Intel® Software Guard Extensions(Intel®SGX) Yes with Intel® ME
    인텔® OS 가드
    인텔® 신뢰 실행 기술 ‡ 아니요
    실행 불능 비트 ‡
    인텔® 부트 가드
  • RAM : 8GB

Ubuntu 20.04 (Host OS)


소스 코드

'Linux > Linux Structure' 카테고리의 다른 글

Chapter 8. 저장 장치  (2) 2021.09.26
Chapter 7. 파일시스템  (0) 2021.09.26
Chapter 6. 메모리 계층  (0) 2021.09.26
Chapter 5. 메모리 관리  (3) 2021.09.26
Chapter 4. 프로세스 스케줄러  (0) 2021.09.26
Linux/Linux Structure 2021. 9. 26. 03:06

Chapter 8. 저장 장치

HDD의 동작 방식

HDD는 플래터platter라고 불리는 자기 장치에 데이터를 자기 정보로 기록하는 저장 장치이다. 데이터는 섹터sector라는 단위(512바이트 or 4KiB)로 읽고 쓴다. 섹터는 동심원 모양으로 원의 중심부터 바깥 방향으로 분할되어 있다.

플래터의 섹터 데이터를 읽으려면, 먼저 스윙 암을 움직여서 자기 헤드를 플래터의 위로 이동시키고, 그 다음 플래터를 회전시켜 자기 헤드를 목적 섹터의 바로 위에 오도록 한다. HDD로의 데이터 전송 흐름은 다음과 같다.

  1. 디바이스 드라이버가 데이터를 HDD에 전달한다. (섹터 번호, 섹터 개수, 읽기 쓰기 등)

  2. 스윙 암을 이동시키고 플래터를 회전시켜 자기 헤드를 섹터 위에 위치시킨다.

  3. 데이터를 읽거나 쓴다.

2, 3번의 경우 기계적 처리이기 때문에, 다른 전기적 처리에 비해 레이턴시가 길다. 즉 레이턴시 중 대부분이 기계적 처리에 걸리는 시간이다.


HDD의 성능 특성

HDD는 연속된 여러 섹터 데이터를 읽을 때, 플래터를 회전하는 것만으로 한 번에 읽을 수 있다. 한 번에 읽을 수 있는 양은 HDD마다 제한이 있다. 이런 특성때문에 파일시스템은 각 파일의 데이터를 최대한 연속된 영역에 배치되도록 한다. 프로그램의 레이턴시를 줄이려면 다음 사항을 생각해야 한다.

  • 파일 내의 데이터를 연속(혹은 가깝게)으로 배치한다.

  • 연속된 영역에는 한 번에 접근한다. (여러번 나눠서 하면 레이턴시 증가)

  • 파일은 큰 사이즈로 시퀀셜sequential하게 접근한다.


HDD 테스트

  • 사용하지 않는 파티션에서 테스트할 것!!

  • umount 명령어로 마운트를 해제해야 테스트할 수 있었다. 마운트된 상태로 테스트하면 device or resource busy 에러가 발생한다.

HDD 테스트 프로그램

측정 내용

  • I/O 사이즈에 따른 성능 변화

  • 시퀀셜 접근 vs 랜덤 접근

테스트 프로그램 사양

  • 지정된 파티션의 처음부터 1GiB까지의 영역에 총 64MiB의 I/O를 요청한다.

  • 파라미터

    • 파일명

    • 커널의 I/O 지원 기능 사용 여부(on / off)

    • 읽기 쓰기(r / w)

    • 접근 패턴(seq / rand)

    • 1회당 I/O 사이즈[KiB]

빌드

아쉽게도 현재 사용 가능한 HDD가 없어서 테스트를 해보지는 못했다. 책 저자의 실험 결과를 바탕으로 정리했다. 직접 해볼 때는 4장에서처럼 log로 남긴 뒤 plot으로 그려보면 좋을 것 같다.

HDD 시퀀셜 접근 테스트

  • 커널의 I/O 지원 기능을 끈 상태로 시퀀셜 접근의 r, w 속도를 측정해본다.

    $ sudo su
    root# for i in 4 8 16 32 64 128 256 512 1024 2048 4096 ;
    for> do time output/io 지정파티션 off r seq $i ; done
    
    root# for i in 4 8 16 32 64 128 256 512 1024 2048 4096 ;
    for> do time output/io 지정파티션 off w seq $i ; done
  • 읽기 쓰기 모두 1회당 I/O 사이즈가 커질수록 스루풋 성능이 향상된다. 하지만 HDD가 한 번에 접근할 수 있는 데이터량의 한계 이상부터는 스루풋이 비슷한데, 이때의 스루풋이 이 HDD의 최대 성능이다.

HDD 랜덤 접근 테스트

  • 커널의 I/O 지원 기능을 끈 상태로 랜덤 접근의 r, w 속도를 측정해본다.

    $ sudo su
    root# for i in 4 8 16 32 64 128 256 512 1024 2048 4096 ;
    for> do time output/io 지정파티션 off r rand $i ; done
    
    root# for i in 4 8 16 32 64 128 256 512 1024 2048 4096 ;
    for> do time output/io 지정파티션 off w rand $i ; done
  • 랜덤 접근의 성능은 시퀀셜 접근보다 전체적으로 떨어진다. 특히 I/O 사이즈가 작을 때 랜덤 접근의 성능이 처참하고, I/O 사이즈가 커질수록 스루풋 성능이 올라간다. I/O 사이즈가 커지면 프로그램의 접근 대기 시간이 줄어들기 때문이다. 그래도 시퀀셜 접근에 비하면 느리다.

블록 장치 계층

리눅스에서는 HDD나 SSD처럼 랜덤 접근이 가능하며 일정 단위로 접근 가능한 장치를 블록 장치라고 분류한다. 이 블록 장치에는 디바이스 파일을 통해 직접 접근하거나 파일시스템을 통해 간접 접근할 수 있다. (대부분은 간접 접근)

블록 장치들에는 공통되는 처리가 많기 때문에, 이를 각 디바이스 드라이버에서 구현하지 않고 커널의 블록 장치 계층에서 처리하여 디바이스 드라이버로 넘긴다.

블록 장치 계층에는 I/O 스케줄러미리 읽기 기능이 있다.

I/O 스케줄러

I/O 스케줄러의 역할

  • 병합(merge) : 연속된 섹터에 대한 I/O 요청을 하나로 모은다.

  • 정렬(sort) : 불연속적인 섹터에 대한 I/O 요청을 섹터 번호 순서대로 정리한다.

I/O 스케줄러는 블록 장치에 대한 접근 요청을 일정 기간동안 모아서, 위의 가공을 한 뒤 디바이스 드라이버에 I/O 요청을 한다. 이러면 I/O 성능이 좋아진다. 정렬 후 병합하는 경우도 있다.

이 I/O 스케줄러 덕분에, 블록 장치의 성능 특성에 대해 자세히 알지 못한 채로 애플리케이션을 개발해도 어느 정도의 I/O 성능은 보장된다.

미리 읽기read-ahead

프로세스에서 데이터에 접근할 때 공간적 국소성Spatial locality이라는 특징이 존재하므로, 이를 이용한 미리 읽기라는 기능이 있다. 특정 영역에 I/O 요청을 하면, 그 바로 뒤의 연속된 영역을 미리 읽어두는 기능이다. 해당 요청 직후에 예측대로 연속된 영역에 접근하면, 이미 데이터 읽기가 되어 있으므로 저장 장치에서의 읽기를 생략할 수 있고, 이를 통해 성능이 향상된다. 예측대로 접근하지 않았을 경우 단순히 읽었던 데이터를 버린다. (명령어 파이프라인과 비슷한 느낌)

커널의 I/O 지원 기능 테스트 - HDD 시퀀셜 접근

  • 커널의 I/O 지원 기능을 켠 상태로 시퀀셜 접근의 r, w 속도를 측정해본다.

    $ sudo su
    root# for i in 4 8 16 32 64 128 256 512 1024 2048 4096 ;
    for> do time output/io 지정파티션 on r seq $i ; done
    
    root# for i in 4 8 16 32 64 128 256 512 1024 2048 4096 ;
    for> do time output/io 지정파티션 on w seq $i ; done
  • I/O 지원 기능을 껐을 때에 비해 스루풋 성능이 엄청나게 향상되었다. I/O 사이즈가 작을 때부터 거의 HDD의 한계까지 성능이 나오는데, 미리 읽기 덕분이다.

  • io 프로그램 실행 중에 다른 터미널로 iostat -x 명령어를 실행하면 미리 읽기에 대한 정보를 관찰할 수 있다.

    $ iostat -x -p 지정파티션 1 # 1초마다 관찰
    $ iostat -x -p nvme0n1p5 1
    Linux 5.13.13-surface (ubun2-Surface-Pro-7)     2021년 09월 25일     _x86_64_    (8 CPU)
    
    avg-cpu:  %user   %nice %system %iowait  %steal   %idle
              4.59    0.01    1.06    0.05    0.00   94.28
    
    Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dkB/s   drqm/s  %drqm d_await dareq-sz  aqu-sz  %util
    nvme0n1p5        4.49    214.47     1.43  24.21    0.24    47.77    7.50    224.07     6.86  47.76    1.67    29.87    0.00      0.00     0.00   0.00    0.00     0.00    0.01   0.77
    • rkB/s 필드가 초당 읽은 용량을 의미한다.

    • 지원 기능을 끈 상태와 켠 상태 두 가지를 비교해보면, 껐을 때는 여러 번에 걸쳐 읽어오고 켰을 때는 한번에 많이 불러오는 것을 알 수 있다. 즉 미리 읽기를 통해 데이터를 메모리에 미리 불러와서 스루풋 성능을 높이는 것이다.

    • rrqm/s 필드가 읽기 처리에 대한 병합 처리량이다. 읽기에 I/O 스케줄러가 동작하는 경우는 여러 프로세스로부터 병렬로 읽기를 하거나, 비동기 I/O 등이므로, 이 테스트 프로그램에서는 병합 기능이 동작하지 않는다.

    • wrqm/s 필드가 쓰기 처리에 대한 병합 처리량이다. 자잘한 I/O 쓰기 요청을 병합하여 일정 사이즈 이상이 되면 HDD의 실제 I/O가 수행되어 쓰기 처리를 고속화한다.

커널의 I/O 지원 기능 테스트 - HDD 랜덤 접근

  • 커널의 I/O 지원 기능을 켠 상태로 랜덤 접근의 r, w 속도를 측정해본다.

    $ sudo su
    root# for i in 4 8 16 32 64 128 256 512 1024 2048 4096 ;
    for> do time output/io 지정파티션 on r rand $i ; done
    
    root# for i in 4 8 16 32 64 128 256 512 1024 2048 4096 ;
    for> do time output/io 지정파티션 on w rand $i ; done
  • 지원 기능을 켜도 I/O 사이즈가 작을 때는 스루풋 성능이 처참하다.

    • 읽기의 경우 미리 읽기를 해도 랜덤 접근으로 연속된 섹터가 아닌 다른 데이터에 대해 읽기 요청을 하므로 미리 읽기한 데이터가 버려지는 것이다.

    • 쓰기의 경우 I/O 사이즈가 작을 때 I/O 스케줄러의 효과가 있기는 하다. 즉 랜덤 접근 중에 우연히 접근 영역이 연속된 I/O 요청에 대해 병합이 발생한다.


SSD의 동작 방식

SSD는 HDD와 달리 전기적으로 데이터에 접근하기 때문에, 스윙 암이나 플래터 등 기계적인 장치가 움직이는 시간이 없다. 즉 전체적으로 성능이 HDD보다 훨씬 빠르며, 랜덤 접근 성능도 좋다.

이 테스트는 sd카드에서 해보려했으나, 쓰기 테스트에서 1분이 넘게 걸리는 것을 보고 제대로 측정이 안된다고 판단하여 책의 내용을 보고 정리하였다.


SSD 테스트

SSD 시퀀셜 접근 테스트

  • 커널의 I/O 지원 기능을 끈 상태로 시퀀셜 접근의 r, w 속도를 측정해본다.

    $ sudo su
    root# for i in 4 8 16 32 64 128 256 512 1024 2048 4096 ;
    for> do time output/io 지정파티션 off r seq $i ; done
    
    root# for i in 4 8 16 32 64 128 256 512 1024 2048 4096 ;
    for> do time output/io 지정파티션 off w seq $i ; done
  • HDD에 비하면 모두 몇 배는 빠르다.

SSD 랜덤 접근 테스트

  • 커널의 I/O 지원 기능을 끈 상태로 랜덤 접근의 r, w 속도를 측정해본다.

    $ sudo su
    root# for i in 4 8 16 32 64 128 256 512 1024 2048 4096 ;
    for> do time output/io 지정파티션 off r rand $i ; done
    
    root# for i in 4 8 16 32 64 128 256 512 1024 2048 4096 ;
    for> do time output/io 지정파티션 off w rand $i ; done
  • 랜덤 접근의 경우 SSD의 스루풋 성능이 HDD보다 훨씬 좋다. 시퀀셜 접근에 비해서는 성능이 낮으나, HDD에서의 경우보다는 그 차이가 적다. 또한 I/O 사이즈가 커지면 시퀀셜 접근과 랜덤 접근의 성능이 비슷해진다.

커널의 I/O 지원 기능 테스트 - SSD 시퀀셜 접근

  • 커널의 I/O 지원 기능을 켠 상태로 시퀀셜 접근의 r, w 속도를 측정해본다.

    $ sudo su
    root# for i in 4 8 16 32 64 128 256 512 1024 2048 4096 ;
    for> do time output/io 지정파티션 on r seq $i ; done
    
    root# for i in 4 8 16 32 64 128 256 512 1024 2048 4096 ;
    for> do time output/io 지정파티션 on w seq $i ; done
  • HDD의 경우와 마찬가지로 I/O 사이즈가 작을 때도 스루풋 성능이 한계에 접근한다. 읽기 성능은 미리 읽기의 효과이고, 쓰기 성능은 I/O 스케줄러가 수행하는 병합 처리의 효과이다.

  • 쓰기에서 I/O 사이즈를 크게 하면 I/O 지원 기능을 껐을 때보다 스루풋 성능이 낮아지는데, 이는 I/O 스케줄러의 오버헤드가 커지기 때문에 발생한다. HDD의 경우에는 기계적 처리의 소요 시간이 이 오버헤드보다 커서 발견하지 못했던 문제점인데, SSD는 전기적 처리로 인한 고속화로 이런 문제점이 보이게 된다.

커널의 I/O 지원 기능 테스트 - SSD 랜덤 접근

  • 커널의 I/O 지원 기능을 켠 상태로 랜덤 접근의 r, w 속도를 측정해본다.

    $ sudo su
    root# for i in 4 8 16 32 64 128 256 512 1024 2048 4096 ;
    for> do time output/io 지정파티션 on r rand $i ; done
    
    root# for i in 4 8 16 32 64 128 256 512 1024 2048 4096 ;
    for> do time output/io 지정파티션 on w rand $i ; done
  • 시퀀셜 접근에 비해서는 당연히 느리지만, 어느정도 I/O 사이즈가 커지면 시퀀셜 접근을 할 때와 성능이 비슷해진다.

  • I/O 지원 기능을 껐을 때와 비교하면, 읽기는 비슷하고(HDD에서의 이유와 같음 - 미리 읽기가 소용없어서) 쓰기는 오히려 성능이 떨어진다. 이는 I/O 스케줄러의 오버헤드를 무시할 수 없고, SSD에서는 정렬의 효과가 별로 없기 때문이다.


정리

사용자가 블록 장치의 원리에 대해 깊게 생각하지 않아도, 커널의 지원 기능 덕분에 어느 정도의 접근 최적화는 이루어진다. 하지만 모든 경우에서 최적의 성능이 나오는 것은 아니며, 바로 위에서처럼 SSD의 경우 특정 상황에서는 I/O 스케줄러의 오버헤드때문에 성능이 오히려 저하되는 경우가 발생할 수 있다.

앞에서도 적었듯 프로그램을 개발할 때에는 다음 사항을 최대한 지키는게 여러모로 좋다.

  • 파일 안의 데이터가 연속되거나 가깝도록 배치한다.

  • 연속된 영역에 대한 접근은 되도록 한 번에 처리한다.

  • 파일에는 최대한 큰 사이즈로 시퀀셜하게 접근한다.


참고


소스 코드

'분류 전체보기'에 해당되는 글 314건