요즘 CLI 로 AI 를 많이 사용하는데..

Gemini 같은 경우 윈도우에 바로 설치가 가능하다(다만 node 가 필요함) 

다만, 우연히 알게된 Amazon Q CLI 를 너무 잘 쓰고 있었는데 노트북을 바꾸면서 새로 설치해야해서 적어본다! 

(Amazon Q CLI 관련한건 아래 링크 확인!!)


1. Windows 기능 켜기/끄기 에서

✅Linux용 Windows 하위 시스템

✅  Virtual Machine Platform(가상 머신 플랫폼)

이 두개를 체크해줍니다!

 

2. 컴퓨터를 재시작해줍니다.

 

4. PowerShell 을 관리자로 실행시킵니다. 

(다른 블로그를 보니  cmd 를 관리자로 실행해도 된다고 하는데 윈도우 에서는 PowerShell 을 기반으로 설명했기에 PowerShell 로합니다!

참고 : https://learn.microsoft.com/ko-kr/windows/wsl/install)

 

5. 명령어로 wsl 을 다운받고 지일 기본이 될 default user 설정을 합니다. 

wsl --install

 

다운 받아지고 있는 상태
default user 셋팅, user 명과 비밀번호 두번 넣기

6. wsl 2를 기본버전으로 설정합니다. 

wsl --set-default-version 2

 

7. 현재 어떠한 설치된 wsl 에 대해 확인하곳 싶을때는 아래 명령어로 확인 가능하다. 

wsl -v -l

 


접속시에는 아래 명령어로 접속하면 된다. 

# 기본 user 로 접속시
wsl 

#여러 user 중 한사람으로 접속시
wsl -u username

 

 

 

참고로 wsl 의 ubuntu 내부의 경로에 있는 파일들은 아래와 같이 파일탐색기에 새로 보이는 Linux 를 클릭하면 확인 가능합니다! 

이렇게 초간단하고 쉬운 윈도우 PC 에 가상 Ubuntu 설치하기 끝났습니다~

 

 

반응형
LIST
MySQL 세션 타임아웃 이슈 분석

문제 상황

유지보수 중인 업체에서 특정 버튼을 클릭하고 해당 작업을 수행하려고 하면 반응이 느리고, 페이지 로딩이 너무너무너무 오래 걸리는 현상이 간헐적으로 발생한다고 함 😭

처음엔 일시적인 문제인 줄 알았는데, 반복적으로 매일 오후에 같은 증상이 나타나는 상황을 발견함.


원인 진단 과정

1️⃣ 프로세스 확인

DB의 lock이 걸려있다는 에러를 기반으로, DB 프로세스를 확인해봄.

SHOW FULL PROCESSLIST;

확인해보니 Sleep 상태로 오랫동안 유지되고 있는 세션이 다수 존재 (몇 시간 동안 지속되고 있었음).

2️⃣ 트랜잭션 점검

SELECT * FROM information_schema.innodb_trx;

즉, 작업이 진행 중인 트랜잭션은 없는데도 연결은 종료되지 않고 남아있던 것!!! 😱

👉 원인 : DB connection이 애플리케이션에서 제대로 닫히지 않아 sleep 상태로 남게 된 것 (정확한 이유는 알 수 없음..)


조치 내용

1️⃣ 장시간 Sleep 상태였던 세션 수동 종료

KILL 1777;
KILL 1787;

2️⃣ DB의 비활성 세션 자동 종료 시간을 5분으로 변경

SET GLOBAL wait_timeout = 300;
  • wait_timeout은 클라이언트가 아무런 요청도 하지 않은 상태로 대기할 수 있는 최대 시간(초 단위)을 의미.
  • 300초 = 5분

3️⃣ 모니터링 결과

이후 한 시간 정도 모니터링 해봤는데 일부 세션(1780, 1783, 1784 등)은 ID는 유지되지만 Time만 갱신되고 있었음.
→ 즉, 해당 ID들은 WAS Connection Pool 내에서 관리되는 연결로 추정되고,
그 외 ID들은 비정상적으로 종료되지 않은 오래된 세션으로 판단됨.


🔎 확인 명령어 정리

(나는 root 계정도 가지고 있어서 가능했던 부분도 있음)

목적 명령어
현재 연결 상태 확인 SHOW FULL PROCESSLIST;
트랜잭션 진행 상태 확인 SELECT * FROM information_schema.innodb_trx;
커넥션 수 확인 SHOW STATUS LIKE 'Threads_connected';
활성 스레드 확인 SHOW STATUS LIKE 'Threads_running';
자동 종료 시간 확인 SHOW VARIABLES LIKE 'wait_timeout';

정리하며 💡

DB에서 나는 문제는 대부분 “조회 쿼리가 너무 오래 걸려서 로딩이 길어지는 경우”가 많았는데, 이번 케이스는 완전히 달랐다 — 구조적인 문제 때문에 일어난 케이스였다.

심지어 MySQL의 기본 설정값 그대로(8시간)인데도 불구하고, 사용자나 네트워크 환경, 또는 애플리케이션 동작 방식에 따라 비정상적으로 종료되지 않은 세션이 계속 쌓이면서 문제가 발생할 수 있다는 걸 알게 됨!

👉 참고로 MySQL의 기본 wait_timeout 값은 28800초 (8시간)이다.


추가 조사 : REPEATABLE-READ 관련

혹시나 MySQLREPEATABLE-READ (기본 격리 수준) 때문인가? 🤔 해서 따로 찾아보았다.

REPEATABLE-READ 특성

  • 한 트랜잭션에서 동일한 SELECT를 여러 번 실행하면 같은 결과를 보장.
  • 이를 위해 InnoDB는 다른 트랜잭션에서 참조 중인 레코드에 잠금을 걸 수 있음.
  • INSERT ... SELECT / CREATE TABLE AS SELECT 같은 전체 테이블 참조 시, MySQL이 해당 테이블을 스냅샷/잠금 처리함.
  • 이때 동시에 다른 트랜잭션이 같은 테이블에 INSERT, UPDATE, DELETE를 시도하면 대기(lock) 상태가 될 수 있음.

결국, 이미 실행 중인 트랜잭션이 테이블을 잠근 상태에서 다른 요청이 들어오면 SLEEP 상태로 대기하는 현상이 발생할 수 있다.

근데 나는 INSERT ... SELECTCREATE TABLE AS SELECT처럼 다른 테이블을 참조하는 쿼리를 쓰지 않아서, 이 부분은 직접적인 원인은 아니었다고 판단됨.
(그래도 이런 경우도 있구나~ 하고 정리만 해둠 ㅎㅎ)


결론적으로, Sleep 세션이 많고 페이지가 느려진다면, 쿼리 튜닝보다는 커넥션 관리 로직부터 점검해보는 게 좋다는 교훈을 얻음 👍

반응형
LIST

인터넷과 떼어 놓을 수 없는 세상에서 ‘URL’이라는 말, 보통 “웹사이트 주소”라고 부르죠.

그런데 가끔 ‘URI’나 ‘URN’이라는 낯선 단어들도 보이는데,


이 셋은 대체 무슨 차이가 있을까? 개발자인 나도 처음엔 헷갈렸던 개념이라, 정리해두려한다! 😁


URI란?

URI (Uniform Resource Identifier)
👉 “인터넷 상의 자원을 식별(Identify) 하는 통합 이름”

쉽게 말해서, 인터넷 어딘가에 있는 ‘무언가’를 가리키는 이름표라고 생각하면 된다. 

예를 들어,

  • 웹사이트 주소
  • 이메일 주소
  • 파일 경로
    이런 것도 모두 URI의 한 종류이다. 

즉, URI는 “무언가를 가리키는 전체 개념이라고 보면 된다. 


URL이란?

URL (Uniform Resource Locator)
👉 “자원의 위치(Location)를 알려주는 URI의 한 종류”

‘Locator’는 위치를 알려준다는 뜻이다. 
그래서 URL은 단순히 “이 자원이 어디에 있어요!” 라고 알려주는 주소이다.

예를 들어:

https://www.example.com:8080/path/page.html?query=test#section2

이 주소를 쪼개보면:


 

부분 의미
https 프로토콜 (어떤 방법으로 접근할지)
www.example.com 도메인 (어디 서버인지)
:8080 포트번호 (선택사항)
/path/page.html 경로
?query=test 쿼리 (추가 정보)
#section2 프래그먼트 (문서 내 특정 위치)

→ 이 전체가 URL,
그리고 이 URL은 URI의 한 종류


URN이란?

URN (Uniform Resource Name)
👉 “위치와 상관없이 자원의 이름(Name) 자체로 식별하는 URI”

예를 들어,
도서관의 책은 어디 선반에 있든 ISBN 번호로 구분할 수 있듯이 
이처럼 ‘어디 있느냐’가 아니라 ‘무엇이냐’로 식별하는 것이 URN이다.

urn:isbn:9783161484100

이건 “ISBN 9783161484100번 책”이라는 고유 이름을 의미합니다.
책이 어느 웹사이트에 있든 상관없이, 이 이름만으로 그 자원을 식별할 수 있어요.


세 가지의 관계 정리

구분 이름 의미 예시
URI 통합 자원 식별자 자원을 식별하기 위한 전체 개념 https://example.com/index.html
urn:isbn:9783161484100
URL 위치 지정자 자원이 어디 있는지를 나타냄 https://example.com/index.html
URN 이름 지정자 자원의 이름으로만 식별 urn:isbn:9783161484100

👉 URIURLURN을 포함하는 더 넓은 개념임! 

 

이미지로 본다면은 이런 느낌? 


마무리

  • URI : 인터넷 자원의 “식별자” 전체 개념
  • URL : 자원의 “위치”로 식별하는 방법
  • URN : 자원의 “이름”으로 식별하는 방법

 

반응형
LIST

 

// 이런 코드가 계속 반복되는 거죠...
dataMap.put( "name", StringUtil.equals(dataBean.getPrivateYn(), "Y") ? "비공개": dataBean.getName() );
dataMap.put( "question", StringUtil.equals(dataBean.getPrivateYn(), "Y") ? "비공개": dataBean.getQuestion() );
dataMap.put( "title", StringUtil.equals(dataBean.getPrivateYn(), "Y") ? "비공개":dataBean.getTitle() );

이번 유지보수 업무를 하다 중복되는 get 메소드를 중복해서 호출해야하는 상황이 있었다.

똑같이 privateYn이 "Y"인지 확인하는 로직인데, 뒤에 불러와야 하는 get 메소드만 getTitle(), getCtgNm1() 등등 다 달랐다. 

 

'어떻게 하면 이 똑같은 로직을 한 번에 해결할 수 있을까?' 고민하다가, 자바 8에 추가된 신박한 기능들을 알게 되어서 정리해봤습니다.

 


1. Supplier<String>: 요청하면 값을 '공급'해줌

Supplier는 자바 8에서 추가된 함수형 인터페이스라는 인데,  말 그대로 '공급자' 역할을 한다.

  • 하는 일: 아무런 입력값 없이, 요청이 오면 특정 타입의 값을 '공급'해줌
  • 사용법: Supplier<T> 형태로 쓰는데, <T>에 우리가 받을 값의 타입을 넣어주면 됨.
    • Supplier<String>: 문자열(String)을 공급해 줘!
    • Supplier<Integer>: 숫자(Integer)를 공급해 줘!

이 안에는 get()이라는 메소드 하나만 있는데, 이 메소드를 호출하면 딱! 정해진 값을 뱉어낸다.

 

나는 그래서 중복된 코드를 줄이기 위해 아래와 같이 코드를 만들었다! 

import java.util.function.Supplier;

public String getPublicValue(ExampleBean bean, Supplier<String> valueSupplier) {
    if ("Y".equals(bean.getPrivateYn())) { // privateYn이 Y면
        return "비공개";                  // 무조건 "비공개"를 반환해!
    } else {                              // 아니면
        return valueSupplier.get();     // Supplier가 공급해주는 값을 반환해줘!
    }
}

2. Supplier는 사용하는 람다! 그 중, :: (메소드 레퍼런스)

 

::는 "메소드 레퍼런스" 라고 부르는 문법인데, 쉽게말해 () -> dataBean.getTitle() 같은 람다식을 더 간단하게 쓸 수 있게 해준다! 

 

람다식(Lambda) 메소드 레퍼런스
() -> dataBean.getTitle() dataBean::getTitle
() -> new ArrayList<String>()
ArrayList::new

 

'객체::메소드' 형태로 사용하는데, " 이 객체의 이 메소드를 쓸꺼야! " 라고 딱 지정해주는 느낌이다! 

위의 Supplier<String> 과 함께 쓰면 아래처럼 위에서 만든 메소드를 사용할 수 있다. 

dataMap.put("title", getPublicValue(dataBean, dataBean::getTitle));
dataMap.put("name", getPublicValue(dataBean, dataBean::getName));
dataMap.put("question", getPublicValue(dataBean, dataBean::getQuestion));

// 람다식을 사용한 예시: 람다식으로는 복잡한 로직도 전달 가능
dataMap.put("question", getPublicValue(dataBean, 
	() -> StringUtils.replace(dataBean.getQuestion(), "\n", " ")));

 

 


4.  왜 Supplier와 ::를 사용해야 할까?

Supplier와 메소드 레퍼런스를 활용하면 다음과 같은 중요한 이점을 얻을 수 있다.

  1. 코드 간결성 및 가독성: 반복되는 코드를 제거하고, 로직을 한 곳에 모아 코드를 더 읽기 쉽게 만듭니다.
  2. 재사용성: 특정 기능을 추상화하여 다양한 곳에서 재사용할 수 있는 유연한 코드를 만들 수 있습니다.
  3. 유지보수성: 로직 변경이 필요할 때 한 곳만 수정하면 되므로, 유지보수가 훨씬 용이해집니다.

 

정말 파도파도 끝이없는 라이브러리들과..함수들... 

매번 할때마다 새롭다...

 

 

 

반응형
LIST

2020년에 샀던 M1칩 맥북이...슬... 발열도 생기고ㅠ...

느려져서.. 맥북 상황을 한눈에 볼 수 있는 어플을 알아보고 있는 와중에 알게된 두가지! 

 

1. iStat Menus

앱스토어에서 다운할 수 있는 CPU, GPU, RAM 등의 상태를 알 수 있는 어플이지만.. 이거에 15000원 정도를..? 하는 생각에 일단 스킵하게되었다.

 

2. ⭐️⭐️⭐️Stats⭐️⭐️⭐️

찾다보니 나온 무료 어플! 무려 깃허브에서 다운받을 수 있다! 

 

깃허브 주소 

https://github.com/exelban/stats

 

GitHub - exelban/stats: macOS system monitor in your menu bar

macOS system monitor in your menu bar. Contribute to exelban/stats development by creating an account on GitHub.

github.com

 

해당 어플에서 모니터 가능한 시스템 정보는 아래와 같다! 

  • CPU utilization
  • GPU utilization
  • Memory usage
  • Disk utilization
  • Network usage
  • Battery level
  • Fan's control (not maintained)
  • Sensors information (Temperature/Voltage/Power)
  • Bluetooth devices
  • Multiple time zone clock

무료에 웹개발 하는데 이정도 확인할 수 있으면 충분하지 않나? 라는 생각에 다운받아보았다 


맥 어플리케이션이기에 terminal에서 homebrew 로 다운 받을 수 있다. 

brew install stats

이런식으로 stats was successfully installed! 라 뜨면 성공!

 

만약 terminal 이 어렵다면은

깃허브에서 이 Manual 부분에서 here 을 클릭하여 dmg 파일을 다운받고 

이런식으로 Applications 에 옮겨주면 간단히 설치가 끝난다 :) 


나는 위와 같이 설정을 해두었다(이후에 어플 설정에서 변경 가눙!)

 

완료되면 이와같은 대시보드가 보여진다 ㅎㅎㅎㅎ 

상단에는 이런식으로 수치가 보여지고 어플내부에서

오른쪽 상단에 토글버튼을 이용해서 끄고 킬 수 있다! 

 

이제...5년된..맥북..에어... 더 잘 써보겠습니다ㅠㅠㅠㅠㅠ 

맥북 사주는 회사로 이직하는 그날까지ㅠㅠㅠㅠㅠ 

반응형
LIST

 


이번에 유지보수를 하고 있는 고객사에서 문의가 들어왔다.
10년 전에 우리가 납품했던 솔루션이 아직도 JDK 1.6 + Spring 3 기반으로 잘 돌아가고 있었는데,
상대방 시스템을 업그레이드하면서 JDK를 Zulu OpenJDK 17로 올리려다 보니 문제가 생긴 거다.

우리 쪽은 현실적으로 업그레이드가 불가능했다.
Spring 3는 JDK 11부터 공식적으로 지원하지 않으니, JDK 버전만 올린다고 해결될 게 아니라
사실상 재개발 수준으로 일이 커져버린다.
그래서 결국 결론은 우리 서버는 현 상태 유지, 상대 서버만 JDK 업그레이드 진행으로 정리했다.

근데 여기서 중요한 포인트가 하나 있었다.
바로 JDK 버전 차이로 인한 TLS 통신 문제.


TLS Handshake 이슈

HTTPS 통신은 데이터를 주고받기 전에 먼저 TLS Handshake 과정을 거친다.
쉽게 말하면 “우리 어떤 규칙으로 보안 통신할래?” 하고 협상을 하는 절차다.

문제는 여기서 TLS 버전이 안 맞으면 아예 대화 자체가 시작이 안 된다.
서로 다른 언어를 쓰는 것처럼, 악수(Handshake)를 하려 해도 손이 안 맞는 상황인 거다.

  • 우리 서버 (WebLogic + JDK 1.6): TLS 1.0 기본
  • 상대 서버 (Zulu OpenJDK 17): TLS 1.2 / 1.3 기본, TLS 1.0은 보안 취약점 때문에 비활성화

즉, 지금 상태로는 TLS 버전이 맞지 않아 연결이 끊어질 수밖에 없다.


TLS Handshake 과정 다이어그램 ✋🤝✋ 

Client (우리 서버)                          Server (상대방 JDK 17)

   | ---- ClientHello (지원 가능한 TLS 버전 목록) ----> |
   | <--- ServerHello (선택된 TLS 버전 응답) --------- |
   | ---- Certificate (서버 인증서 전달) ------------->|
   | <--- Key Exchange (세션 키 교환) ---------------- |
   | ---- Finished (암호화 시작 준비 완료) ----------> |
   | <--- Finished (암호화 시작 준비 완료) ----------- |

          이후 암호화된 HTTPS 통신 시작 🔒
 
 
 👉 보면 알겠지만, 결국 양쪽이 합의한 TLS 버전으로 내려가야 정상 통신이 가능하다.

근데 지금은 애초에 지원하는 버전 자체가 안 맞으니 손도 못 잡는 상황인 거다.


JDK 버전별 TLS 지원 정리 📑


JDK 버전 기본 지원  TLS 버전특징
JDK 1.6 TLS 1.0 (기본) TLS 1.1/1.2는 추가 패치와 설정 필요
JDK 1.7 TLS 1.0, 1.1 1.2 지원 가능 (업데이트 적용 시 안정적)
JDK 1.8 TLS 1.2 (기본) 가장 널리 사용, TLS 1.3은 불가
JDK 11 TLS 1.2, 1.3 TLS 1.3 지원, 보안 기본값 강화
JDK 17 TLS 1.2, 1.3 최신 보안 표준 준수, 1.0/1.1 기본 비활성화

👉 이 표만 봐도 답이 나온다.
JDK 1.6은 TLS 1.2 이상을 원활하게 쓰기가 어렵고,
JDK 17은 최신 보안 정책 때문에 TLS 1.0/1.1을 아예 막아둔 경우가 많다.


TLS가 왜 중요한가? 🔒

“그냥 데이터만 오가면 되는 거 아닌가?” 싶을 수 있는데,
TLS는 사실 보안 통신의 기본 뼈대다.

  1. 암호화 (Encryption) → 중간에서 패킷을 훔쳐봐도 내용은 해독 불가
  2. 무결성 (Integrity) → 데이터가 전송 중에 변조되지 않았음을 보장
  3. 인증 (Authentication) → 내가 통신하는 대상이 진짜 서버가 맞는지 확인

즉, TLS가 안 맞으면 단순히 연결 실패 문제가 아니라
보안적으로 구멍이 크게 뚫린다는 의미다.


해결 방법: WebLogic에서 TLS 1.2 켜주기 🛠️

다행히 방법이 아주 없는 건 아니다.
JDK 1.6이라고 해도, 몇 가지 설정을 추가하면 TLS 1.2를 쓸 수 있다.

  • JCE Unlimited Strength Policy 설치
  • WebLogic JVM 옵션에 프로토콜 강제 지정

예시 옵션:

-Dhttps.protocols=TLSv1.2
 

이렇게 세팅해주면 우리 서버도 TLS 1.2로 통신할 수 있고,
상대방 서버가 JDK 17로 업그레이드되더라도 API 연동은 계속 이어갈 수 있다.


이번 경험에서 느낀 점 📝

이번 건으로 확실히 깨달았다.
JDK 업그레이드는 단순히 “버전만 올리면 끝”이 아니라,
TLS 같은 보안 프로토콜 호환성 문제까지 따라온다는 거다.

특히 10년 넘은 구 시스템을 유지보수하는 입장이라면,
상대 시스템이 기술 스택을 바꾸기 전에 TLS 환경부터 확인하는 게 안전하다.

👉 비슷한 상황이 있다면 꼭 체크해라.
“상대 JDK 버전 ↔ 우리 서버 TLS 버전” 이거 먼저 확인하는 게 답이다.

반응형
LIST

+ Recent posts