반응형

fs.createReadStream + csv-parser 사용 시 비동기 처리에 주의하세요!


📌 문제 상황: 비동기 스트림에서 예상치 못한 동작

CSV 파일을 읽고, 특정 수량(quantity)만큼 데이터를 처리하려고 했지만, 모든 데이터가 처리됨. 😲

목표:

  • CSV 데이터에서 특정 개수(quantity)만 읽고 중단
  • 비동기 함수(await)가 정확히 작동하도록 수정

💥 문제 발생 코드: 비동기 흐름 제어 실패

import fs from 'fs';
import csv from 'csv-parser';

let count = 0;
const quantity = 20;
const winDataList: any[] = [];

fs.createReadStream(filePath)
  .pipe(csv())
  .on("data", async (data: CsvRow) => {
    if (count < quantity) {
      const email = data.email;
      const point = data.point;
      const choice = data.choice;
      const choiceImage = { a: "imagea", b: "imageb" }[choice]!;

      winDataList.push({ email, point, choice, choiceImage });
      console.log("Processing:", email, point);

      await updateEmailFile(email, fileName); // 비동기 작업
      await updateEmail(email);              // 비동기 작업

      count++;
    } else {
      return; // ❌ 스트림은 계속 실행됨
    }
  });

⚠️ 문제 원인:

  1. csv-parser는 비동기 흐름을 기다리지 않음.
  2. await 사용했지만, 스트림은 비동기 작업과 무관하게 계속 실행.
  3. 결과: 모든 CSV 데이터가 처리됨. 😱

해결 방법: 스트림 흐름을 명확히 제어

### 🎯 방법 1: stream.destroy()로 스트림 종료

count가 quantity에 도달하면 스트림 자체를 종료하여 추가 데이터를 읽지 않도록 합니다.

import fs from 'fs';
import csv from 'csv-parser';

let count = 0;
const quantity = 20;
const winDataList: any[] = [];

const stream = fs.createReadStream(filePath)
  .pipe(csv());

stream.on("data", async (data: CsvRow) => {
  if (count < quantity) {
    const email = data.email;
    const point = data.point;
    const choice = data.choice;
    const choiceImage = { a: "imagea", b: "imageb" }[choice]!;

    winDataList.push({ email, point, choice, choiceImage });
    console.log("Processing:", email, point);

    await updateEmailFile(email, fileName);
    await updateEmail(email);

    count++;

    if (count >= quantity) {
      stream.destroy(); // ✅ 스트림 완전 종료
    }
  }
});

stream.on("close", () => {
  console.log("Stream closed after processing", count, "items.");
});

stream.on("error", (err) => {
  console.error("Stream error:", err);
});

💡 장점:

  • 간단하고 빠른 구현
  • quantity에 도달하면 즉시 스트림 종료

단점:

  • 스트림 완전 종료: 이후 데이터는 절대 다시 읽을 수 없음

### 🎯 방법 2: pause() & resume()으로 정교한 제어

각 데이터 처리 시 스트림을 일시정지하고, 비동기 작업 완료 후 다시 재개합니다.

import fs from 'fs';
import csv from 'csv-parser';

let count = 0;
const quantity = 20;
const winDataList: any[] = [];

const stream = fs.createReadStream(filePath)
  .pipe(csv());

stream.on("data", async (data: CsvRow) => {
  if (count < quantity) {
    stream.pause(); // ✅ 데이터 흐름 일시 정지

    const email = data.email;
    const point = data.point;
    const choice = data.choice;
    const choiceImage = { a: "imagea", b: "imageb" }[choice]!;

    winDataList.push({ email, point, choice, choiceImage });
    console.log("Processing:", email, point);

    await updateEmailFile(email, fileName);
    await updateEmail(email);

    count++;

    if (count >= quantity) {
      stream.destroy(); // ✅ 최대 수량 도달 시 스트림 종료
    } else {
      stream.resume(); // ✅ 다음 데이터 읽기 재개
    }
  }
});

stream.on("close", () => {
  console.log("Stream closed after processing", count, "items.");
});

stream.on("error", (err) => {
  console.error("Stream error:", err);
});

💡 장점:

  • 비동기 흐름 제어 가능 (데이터 순서 보장)
  • 중간에 작업 재개 가능

단점:

  • 코드 복잡성 증가

🎯 방법 3: pipeline()으로 스트림 관리 최적화

Node.js 10+에서는 **stream.pipeline()**을 사용해 에러 핸들링비동기 흐름 관리를 더 효율적으로 처리할 수 있습니다.

import { createReadStream } from 'fs';
import { pipeline } from 'stream';
import csv from 'csv-parser';
import { promisify } from 'util';

const asyncPipeline = promisify(pipeline);

async function processCSV(filePath: string, quantity: number) {
  let count = 0;
  const winDataList: any[] = [];

  await asyncPipeline(
    createReadStream(filePath),
    csv(),
    async function* (source) {
      for await (const data of source) {
        if (count >= quantity) break;

        const email = data.email;
        const point = data.point;
        const choice = data.choice;
        const choiceImage = { a: "imagea", b: "imageb" }[choice]!;

        winDataList.push({ email, point, choice, choiceImage });
        console.log("Processing:", email, point);

        await updateEmailFile(email, fileName);
        await updateEmail(email);

        count++;
      }
    }
  );

  console.log("Processed", count, "records");
}

processCSV(filePath, 20).catch(console.error);

💡 장점:

  • 에러 핸들링 포함
  • 비동기 흐름 자연스럽게 제어 가능
  • 중간에 멈추거나 재시작 가능

단점:

  • Node.js 10+ 필요
  • 복잡한 로직에는 적합하지 않을 수 있음

결론: 어떤 방법을 선택할까?

방법장점단점추천 상황

stream.destroy() 빠르고 단순 이후 데이터 다시 읽기 불가 간단한 데이터 처리
pause() & resume() 비동기 흐름 제어, 순서 보장 코드 복잡성 증가 정교한 흐름 제어 필요 시
pipeline() 에러 핸들링, 비동기 흐름 최적화 Node.js 10+ 필요 대규모 스트림 작업

📊 💡 최종 추천

  • 빠르게 끝내야 한다면 → destroy()
  • 비동기 흐름을 제어하고 싶다면 → pause() & resume()
  • 에러 핸들링과 확장성을 고려한다면 → pipeline()

💬 마무리

Node.js의 스트림은 효율적인 데이터 처리를 가능하게 하지만, 비동기 흐름 관리에 유의해야 합니다. 특히 대용량 CSV 처리에서는 pause()와 destroy()를 적절히 사용하여 메모리 사용을 줄이고, 필요 시 pipeline()으로 에러 핸들링까지 고려하세요. 🚀

 

#NodeJS #JavaScript #CSVParsing #StreamAPI #AsyncProgramming #DataProcessing #BackendDevelopment #NodeJSTips #FullStackDevelopment #WebDevelopment #Asynchronous #CodingTips #DeveloperLife #CodeOptimization #ErrorHandling #NodeJSTutorial #BackendEngineer #ProgrammingTips #SoftwareEngineering #TechBlog

💡 활용 팁:

  • 기술 태그 (#NodeJS, #JavaScript, #StreamAPI) → 개발자 타겟팅
  • 문제 해결 태그 (#ErrorHandling, #CodeOptimization) → 검색 최적화
  • 커뮤니티 태그 (#DeveloperLife, #TechBlog) → 더 넓은 도달범위 확보
728x90
반응형
반응형

기업이 자기 주식을 직접 사들이는 **자기주식취득(Self-Stock Repurchase)**이란 무엇일까요? 주주가치를 높이고 주가를 안정화하는 효과적인 전략으로 활용되는 자기주식취득은 많은 기업이 실행하는 중요한 금융 정책 중 하나입니다. 이번 포스트에서는 자기주식취득의 개념, 목적, 방법, 그리고 장단점까지 자세히 살펴보겠습니다.


1. 자기주식취득이란?

자기주식취득은 기업이 시장에서 유통되고 있는 자사 주식을 직접 매입하는 행위를 의미합니다. 이는 주주가치 제고와 주가 부양을 목적으로 하며, 다양한 이유로 기업이 선택하는 전략 중 하나입니다.

기업이 자기주식을 매입하면 유통 주식 수가 줄어들고, 주당순이익(EPS)이 증가할 가능성이 있습니다. 또한, 적대적 인수합병(M&A)을 방어하거나 잉여현금을 효과적으로 활용하는 방법으로도 사용됩니다.


2. 기업이 자기주식을 취득하는 이유

① 주가 부양 및 주주가치 증대

자기주식을 취득하면 시장에서 유통되는 주식 수가 줄어들어 주당가치가 상승할 수 있습니다. 이는 주가 상승 효과를 가져올 가능성이 크며, 투자자들에게 긍정적인 신호를 줄 수 있습니다.

② 잉여현금 활용 및 자본구조 최적화

기업이 이익을 많이 냈지만 적절한 투자처가 없을 경우, 현금을 활용하여 자기주식을 매입하는 방법이 있습니다. 이는 배당금 지급과 비슷한 효과를 가져오면서도 자본구조를 최적화하는 데 도움이 됩니다.

③ 적대적 M&A 방어

자기주식을 많이 보유하면 외부 기업이 적대적 인수합병을 시도하는 것을 방어하는 효과를 가질 수 있습니다. 이는 기업 경영진이 경영권을 보호하는 중요한 전략이 될 수 있습니다.

④ 스톡옵션 지급을 위한 확보

기업은 임직원에게 보상으로 주식을 지급하는 경우가 많습니다. 자기주식을 매입하면 기존 주식을 활용하여 스톡옵션을 지급할 수 있으며, 새로운 주식을 발행하는 부담을 줄일 수 있습니다.


3. 자기주식취득의 방법

기업이 자기주식을 취득하는 방법은 다음과 같이 네 가지가 있습니다.

① 직접 시장에서 매입

가장 일반적인 방법으로, 기업이 정해진 기간 동안 공개적으로 자사 주식을 매입하는 방식입니다. 이는 공시된 계획에 따라 시장에서 점진적으로 이루어집니다.

② 공개매수(Tender Offer)

기업이 특정 가격을 제시하고, 주주들이 이에 응하면 해당 가격으로 주식을 매입하는 방식입니다. 주주들에게 시장 가격보다 높은 가격을 제시하여 적극적으로 참여를 유도하는 경우가 많습니다.

③ 대주주 및 계열사로부터 직접 매입

기업이 대주주나 계열사 보유 지분을 직접 인수하는 방식으로, 내부 거래 규정에 따라 투명하게 진행되어야 합니다.

④ 장외거래(Over-the-Counter, OTC)

기업이 시장을 통하지 않고 개별적으로 주식을 매입하는 방식으로, 특정 기관 투자자 또는 대주주와 협의를 통해 이루어집니다.


4. 자기주식취득의 장점과 단점

✅ 자기주식취득의 장점

  • 주당순이익(EPS) 증가: 유통 주식 수가 감소하면 EPS가 상승할 가능성이 있습니다.
  • 주주가치 증대: 배당과 같은 효과를 제공하여 주주에게 혜택을 줍니다.
  • 주가 상승 가능성: 기업이 자사 주식을 매입하면 주가가 상승할 가능성이 높아집니다.
  • 자본구조 최적화: 기업이 불필요한 현금을 활용하여 재무구조를 최적화할 수 있습니다.

❌ 자기주식취득의 단점

  • 현금 유동성 감소: 기업이 현금을 사용하여 주식을 매입하면 단기적인 자금 유동성이 줄어들 수 있습니다.
  • 장기적 성장 기회 손실: 자기주식을 매입하는 데 자금을 사용하면 R&D 또는 신규 투자 기회가 줄어들 수 있습니다.
  • 주가 조작 가능성: 일부 기업이 주가 부양을 목적으로 자기주식취득을 악용할 가능성이 있습니다.

5. 자기주식취득과 자기주식 소각의 차이

자기주식취득과 자기주식 소각은 비슷해 보이지만, 중요한 차이가 있습니다.

구분자기주식취득자기주식소각

개념 기업이 시장에서 자사 주식을 매입하는 행위 매입한 자기주식을 소각하여 발행 주식 수를 영구적으로 줄이는 행위
유통 주식 수 단기적으로 감소, 하지만 재판매 가능 영구적으로 감소
회계 처리 자본의 차감 항목으로 기록 자본금 감소
주가 영향 주가 상승 가능성이 있지만 재판매 시 하락 가능 주당가치(EPS) 상승 효과가 강함

기업이 자기주식을 단순히 보유하는 경우 나중에 다시 매각할 수 있지만, 소각하면 영구적으로 유통 주식 수가 줄어들게 됩니다.


6. 기업들이 자기주식취득을 자주 하는 이유

최근 많은 기업들이 자기주식취득을 적극적으로 활용하는 이유는 다음과 같습니다.

  • 주주친화 정책 강화: 자기주식취득은 배당과 함께 주주들에게 혜택을 주는 방법입니다.
  • 주가 방어: 주가가 저평가되었다고 판단할 경우, 기업이 자기주식을 매입하여 주가를 방어할 수 있습니다.
  • 적대적 M&A 방어: 기업이 자기주식을 확보하면 경영권 방어에 활용할 수 있습니다.
  • 자본구조 최적화: 불필요한 현금을 활용하여 부채비율을 조정하고, 재무 건전성을 높일 수 있습니다.

결론

자기주식취득은 기업이 주주가치를 증대하고, 주가를 부양하며, 자본구조를 최적화하는 데 중요한 역할을 합니다. 하지만 단기적인 현금 유출과 장기적인 성장 기회 상실 등의 리스크도 존재하기 때문에, 투자자들은 기업의 자기주식취득 공시를 신중하게 분석해야 합니다.

자기주식취득은 단순한 주가 부양 수단이 아니라, 기업의 장기적인 전략과 맞물려 활용되는 중요한 금융 정책입니다. 따라서 투자자들은 기업이 어떤 의도로 자기주식을 취득하는지를 면밀히 살펴보는 것이 중요합니다.

728x90
반응형
반응형

JavaScript를 포함한 대부분의 프로그래밍 언어는 IEEE 754 표준에 따른 이중 정밀도 부동소수점(floating point) 방식을 사용합니다. 이 방식은 실수를 이진수로 표현하는데, 모든 소수를 정확하게 표현할 수 없기 때문에 내부적으로 약간의 오차가 발생합니다.

예를 들어, 아래와 같이 0.2와 0.4를 더하면:

const result = 0.2 + 0.4;
console.log(result); // 0.6000000000000001

 

왜 정확히 0.6이 나오지 않을까요? 그 이유는 0.2와 0.4를 이진수로 표현할 때 무한소수로 나타나기 때문에 반올림 과정에서 미세한 오차가 누적되기 때문입니다.

부동소수점 오차의 원인

IEEE 754 표준에서는 모든 숫자를 2진법으로 표현합니다. 그러나 10진법의 소수 중에는 2진법으로 정확하게 표현할 수 없는 수들이 있습니다. 예를 들어,

  • 0.2는 2진수로 근사치로 표현되고,
  • 0.4 역시 근사치로 표현됩니다.

이러한 근사치 계산 과정에서 오차가 발생하고, 두 값을 더할 때 오차가 누적되어 예상치 못한 결과가 나오게 됩니다.

해결 방법

부동소수점 연산 오차 문제를 완화하기 위한 몇 가지 방법을 소개합니다.

1. 반올림 사용하기

연산 결과를 원하는 소수점 자리수로 반올림하는 방법입니다. Number.prototype.toFixed() 메서드를 사용하면 문자열로 반환되므로, 이를 Number() 함수를 통해 숫자형으로 변환할 수 있습니다.

const result = 0.2 + 0.4;
const rounded = Number(result.toFixed(2)); // 소수점 둘째 자리까지 반올림
console.log(rounded); // 0.6

이 방법은 결과 값을 표현할 때는 유용하지만, 연산 자체의 정확도를 높이는 방법은 아닙니다.

2. 정수 연산 후 나누기

실수를 직접 계산하는 대신 정수 연산을 한 후 최종 결과를 원하는 단위로 변환하는 방법입니다.

const result = (2 + 4) / 10;
console.log(result); // 0.6

이 방법은 소수점 이하의 연산을 정수로 처리하여 부동소수점 오차를 피할 수 있는 장점이 있습니다. 그러나 모든 경우에 적용하기는 어려울 수 있습니다.

3. 수학 라이브러리 사용하기

보다 정밀한 계산이 필요하거나 부동소수점 오차를 완전히 제어하고 싶다면, Decimal.jsBig.js와 같은 라이브러리를 사용하는 것이 좋습니다.

Big.js 예제:

const Big = require('big.js');

const result = Big(0.2).plus(Big(0.4));
console.log(result.toString()); // "0.6"

// 결과를 number 타입으로 변환하려면:
const numberResult = Number(result);
console.log(numberResult); // 0.6

이 방법은 라이브러리 내부에서 소수 연산의 오차를 보완하는 알고리즘을 사용하므로, 보다 신뢰할 수 있는 결과를 제공합니다.


결론

JavaScript의 부동소수점 연산은 IEEE 754 표준에 의해 발생하는 오차 때문에, 0.2 + 0.4의 결과가 0.6000000000000001로 나타납니다. 이러한 문제를 해결하기 위해서는:

  1. 반올림을 통해 원하는 자리수로 결과를 조정하거나,
  2. 정수 연산 후 나누기 방식을 사용하거나,
  3. Decimal.js, Big.js와 같은 수학 라이브러리를 활용하여 보다 정밀한 계산을 수행하는 방법이 있습니다.

상황에 따라 적절한 방법을 선택하여 부동소수점 연산 오차 문제를 완화할 수 있습니다.

 

 

728x90
반응형
반응형

 

2025년 산티니 충주 그란폰도 접수가 코앞으로 다가왔네요. 후반기 그란폰도는 충주그란폰도만 참가했으면 하는데 접수령을 넘을 수 있었으면 좋겠습니다.

올해 그란폰도 져지 사이즈 발표도 됐는데 작년에 비해 더 세분화 되었더라고요.

2025년 산티니 충주란폰도 져지 시이즈표 - https://chungjugf.co.kr/

 

충주 그란폰도

충주 그란폰도, GRAN FONDO, 대회 안내, 개인, 단체 참가, 충주시 자전거 연맹

chungjugf.co.kr

 

작년에 없던 5XL, 6XL가 생겼습니다. 

2024년 산티니 충주그란폰도 져지 사이즈표 - 남자

작년에는 L 사이즈를 신청했었는데 살짝 크다는 생각을 했었고 입었을때 조금 편한 스포츠용 티셔츠를 입은 느낌이였는데요

타이트한걸 좋아하는 분은 많이 아쉬웠을 사이즈였다고 생각되네요.

새로 생긴 사이즈를 제외하면 동일한 스펙이라 M 사이즈를 신청하려고 했는데 오늘 다시 입어보니 살이 더 쪄서 그런지 적당한 느낌이 드는건 왜일런지

참고로 저는 170 / 80에 작고 뚠뚠한 사람입니다. 

신청할때 사이즈 고민이 되실까봐 참고하시라고 겸사겸사 올려보네요.

올해는 살 빼는걸로 

 

728x90
반응형
반응형

1. CA 생성 시 입력하는 패스워드

역할 및 목적
CA(Certificate Authority)를 생성할 때 입력하는 패스워드는 CA의 개인 키를 암호화하는 데 사용됩니다. 예를 들어, elasticsearch-certutil ca 명령어를 통해 CA 인증서를 만들 때, 이 패스워드는 CA의 개인 키(예: http_ca.key)를 안전하게 암호화하여 저장합니다. 이후, CA를 이용해 다른 인증서를 서명할 때도 이 암호가 필요할 수 있습니다.

사용 시점과 영향

  • 사용 시점: 주로 CA 관련 작업, 예를 들어 새로운 인증서를 서명하거나 CA 인증서를 재발급할 때 필요합니다.
  • 실행 후 영향: 이 패스워드는 CA의 개인 키를 보호하는 역할을 하며, 운영 중에는 CA 관련 작업이 발생하지 않는 한 별도의 런타임 영향은 없습니다.

2. Elasticsearch keystore의 xpack.security.http.ssl.keystore.secure_password

역할 및 목적
이 설정은 Elasticsearch가 HTTPS 통신에 사용하는 HTTP keystore(예: http.p12) 파일을 열 때 사용됩니다. keystore 파일에는 HTTP 인증서와 그에 대응하는 개인 키가 포함되어 있으며, 이를 통해 Elasticsearch는 안전한 HTTPS 연결을 설정합니다.

사용 시점과 영향

  • 사용 시점: Elasticsearch가 시작할 때 keystore 파일을 열어 HTTPS 연결을 위한 인증서와 개인 키를 읽어들일 때 이 패스워드가 사용됩니다.
  • 실행 후 영향: 만약 이 패스워드가 올바르지 않다면, Elasticsearch는 keystore를 열 수 없게 되어 HTTPS 연결을 설정하지 못합니다. 그 결과 클라이언트(예: Kibana)와의 보안 통신에 문제가 발생할 수 있습니다.

3. 두 패스워드는 서로 달라도 괜찮은가?

두 패스워드는 각각 완전히 다른 역할을 수행합니다.

  • CA 패스워드: CA의 개인 키를 암호화하여 보호하며, CA 관련 서명 작업에 사용됩니다.
  • Keystore 패스워드: Elasticsearch가 HTTPS 통신에 필요한 인증서와 개인 키가 저장된 keystore 파일을 열 때 사용됩니다.

따라서 보안 정책에 따라 두 패스워드는 반드시 동일할 필요는 없으며, 서로 독립적으로 관리하는 것이 일반적입니다.


결론

보안 설정을 보다 명확하게 구성하기 위해서는 각 패스워드의 역할과 사용 시점을 정확히 이해하는 것이 중요합니다.

  • CA 생성 시 입력하는 패스워드: CA의 개인 키 암호화 및 서명 작업에 사용.
  • xpack.security.http.ssl.keystore.secure_password: Elasticsearch가 HTTPS 통신을 위해 keystore 파일을 열 때 사용.
728x90
반응형
반응형

 

방법은 CA부터 만들고 elasticsearch-certutil http에서 생성한  CA를 선택해서 진행하는 방식과

elasticsearch-certutil http로 바로 시작해서 CA를 만들면서 시작하는 방식이 있는데 공식문서에는 첫번재 방식에 대해서 자세히 설명이 되어 있지만 저는 두번째 방식으로 진행했습니다.

 

우분투 18.04에 elasticsearch와 kibana만 설치하고 진행했습니다.

#우분투에 설치된 경로 기준
sudo /usr/share/elasticesearch/bin/elasticsearch-certutil htt

해당 명령어를 입력하면 인증서를 만들기 위해 옵션 설정 항목들이 나옵니다.

## Elasticsearch HTTP Certificate Utility

# Do you wish to generate a Certificate Signing Request (CSR)?
Generate a CSR? [y/N]n

## Do you have an existing Certificate Authority (CA) key-pair that you wish to use to sign your certificate?
Use an existing CA? [y/N]n

## CA Generation Options
Do you wish to change any of these options? [y/N]n

## CA password
CA password:  [<ENTER> for none] 패스워드입력
Repeat password to confirm: 패스워드입력

## How long should your certificates be valid?
For how long should your certificate be valid? [5y] 2y

## Do you wish to generate one certificate per node?
Generate a certificate per node? [y/N]n

## Which hostnames will be used to connect to your nodes?
localhost

Is this correct [Y/n]y

## Which IP addresses will be used to connect to your nodes?
127.0.0.1

Is this correct [Y/n]y

## Other certificate options
Do you wish to change any of these options? [y/N]n

## What password do you want for your private key(s)?
Provide a password for the "http.p12" file:  [<ENTER> for none] 패스워드입력
Repeat password to confirm: 패스워드입력

## Where should we save the generated files?
What filename should be used for the output zip file? [/usr/share/elasticsearch/elasticsearch-ssl-http.zip] 엔터

마지막 output zip file 에서 파일명 변경없이 엔터 치면 Zip file written to /usr/share/elasticsearch/elasticsearch-ssl-http.zip 메시지와 함께 제안해준 파일이 생성이 됩니다.

sudo unzip /usr/share/elasticsearch/elasticsearch-ssl-http.zip -d /etc/elasticsearch/certs/http

압축파일을 /etc/elasticsearch/certs/http 아래에 풀었는데요 기본적으로 /etc/elasticsearch/certs까지 구성되어 있기 때문에 http 디렉토리를 먼저 만들고 진행하면 됩니다.

Archive:  /usr/share/elasticsearch/elasticsearch-ssl-http.zip
   creating: /etc/elasticsearch/certs/http/elasticsearch/
  inflating: /etc/elasticsearch/certs/http/elasticsearch/README.txt  
  inflating: /etc/elasticsearch/certs/http/elasticsearch/http.p12  
  inflating: /etc/elasticsearch/certs/http/elasticsearch/sample-elasticsearch.yml  
   creating: /etc/elasticsearch/certs/http/ca/
  inflating: /etc/elasticsearch/certs/http/ca/README.txt  
  inflating: /etc/elasticsearch/certs/http/ca/ca.p12  
   creating: /etc/elasticsearch/certs/http/kibana/
  inflating: /etc/elasticsearch/certs/http/kibana/README.txt  
  inflating: /etc/elasticsearch/certs/http/kibana/elasticsearch-ca.pem  
  inflating: /etc/elasticsearch/certs/http/kibana/sample-kibana.yml

압축을 풀면 위와 같이 어떤 파일들이 압축해제 되었는지 보여줍니다. 

파일들에 대해서 요약해보자면 

  • Elasticsearch 관련 파일 (/elasticsearch/ 디렉터리)
    • http.p12: Elasticsearch HTTP 통신에 사용할 인증서와 개인 키.
    • sample-elasticsearch.yml: 해당 인증서를 사용하는 설정 예시.
  • CA 관련 파일 (/ca/ 디렉터리)
    • ca.p12: Elasticsearch HTTP 인증서를 서명한 CA 정보가 담긴 키스토어.
  • Kibana 관련 파일 (/kibana/ 디렉터리)
    • elasticsearch-ca.pem: Kibana가 Elasticsearch의 인증서를 검증할 때 사용하는 CA 인증서.
    • sample-kibana.yml: Kibana의 SSL/TLS 설정 예시 파일.
sudo vi /etc/elasticsearch/elasticsearch.yml

elasticsearch.yml  파일을 열어서 keystore.path 설정 변경을 해줍니다.

xpack.security.http.ssl:
	enabled: true
    keystore.path: certs/http/elasticsearch/http.p12

그리고 Elasticsearch의 보안 설정에 개인 키의 비밀번호를 추가합니다.

sudo /usr/share/elasticsearch/bin/elasticsearch-keystore add xpack.security.http.ssl.keystore.secure_password

기존에 생성되어 있는 키가 있기때문에 덮어씌우기하시면 됩니다.

sudo systemctl restart elasticsearch

elasticsearch를 재시작해하면 elasticsearch와 관련된 설정은 끝이고 kibana 설정을 해보겠습니다.

sudo cp /etc/elasticsearch/certs/http/kibana/elasticsearch-ca.pem /var/lib/kibana/

압축파일에 있던 인증서를 복사합니다.

sudo openssl x509 -in /var/lib/kibana/elasticsearch-ca.pem -noout -fingerprint -sha256

설정파일을 수정할때 ca_trusted_fingerprint값도 바꿔야 하기때문에 미리 출력합니다.

sudo vi /etc/kibana/kibana.yml

kibana.yml파일을 열어서 기존에 있던 인증서 설정값을 새로운 인증서로 변경합니다.

elasticsearch.ssl.certificateAuthorities: [/var/lib/kibana/elasticsearch-ca.pem]
xpack.fleet.outputs:[{......, ca_trusted_figerprint: "sha256 값"
sudo systemctl restart kibana

kibana를 재실행 하면 설정은 끝납니다.

 

 

728x90
반응형
반응형

페플의 메테오 컴팩트 실켓 반팔 티셔츠를 좋아하는데 물량부족으로 구매가 어렵게 되어 대체할 수 있는 티셔츠를 구매해 보았는데요.

구매한 제품은 샤카웨어 맥스 헤비 웨이트 반팔 티셔츠와 자바나스의 익스트림 USA코튼 티셔츠 입니다.

 

샤카웨어는 얇은 비닐에 담겨있는데 자바나스는 조금 더 두께감이 있는 지퍼백에 담겨있는데 이 부분이 맘에 드네요.

가격차이가 있긴 하지만 자바나스도 저렴한 편이라 이란 소소함이 브랜드의 가치를 높여주는 요소 중 하나이지 않을까요.

 

 

사이즈는 둘다 L 사이즈로 구매 보았습니다.

넥라인 늘어남 비교

사진으로는 늘어남의 표현이 한계가 느껴지지만 샤카웨어의 넥이 부드럽게 잘 늘어났습니다. 

저는 개인적으로 쫀쫀한걸 선호하기 때문에 샤카웨어보단 자바나스가 더 맘에 드네요.

 

박음질 비교

공부가 필요한 부분이네요. 기존에는 그리 신경쓰지 않았는데 추천 글이나 영상에 보면 이런 박음질도 중요하게 보더라고요.

두께 비교

손으로 만져봐도 느낄 수 있을만큼 자바나스가 두꺼웠습니다. 

길이비교

길이는 샤카웨어가 더 길었습니다. 입어보면 정말 길었습니다.

가슴단면 비교

스펙에 나와있는 단면 길이는 샤카웨어는 56cm 자바나스는 59.5cm

스펙처럼 자바나스 티셔츠의 폭이 조금 더 큽니다.

자바나스 쇼핑몰에선 체중이 75~80kg 사이일때 세미 오버핏을 원하면 L사이즈를 선택하면 된다고 되어 있는데 딱 그 정도 인거 같았습니다. 적당히 체형 커버 되고 길이도 적당했습니다.

샤카웨어는 가슴단면은 조금 더 작기에 단품으로 입기보단 이너용으로 더 나을거 같은 느낌이였습니다. 키가 작고 체형이 큰 사람에게는 안어울리겠구나란 생각이 들 정도로 사이즈가 언발란스한 느낌이였네요.

저는 쫀쫀하고 두께감 있는걸 선호하기에 자바나스 익스트림 USA코튼 티셔츠가 만족스러웠습니다.

기존에 페플의 메테오 컴팩트 실켓 반팔 티셔츠를 입었는데 인기가 많아서 인지 구매하는데 원하는 사이즈가 없더라고요. 그 티셔츠를 대체하기에 좋은 선택이 되겠다 싶습니다.

 

 

728x90
반응형
반응형

JavaScript에서 forEach는 일반적인 for 루프와 달리 break를 사용할 수 없습니다. 하지만 forEach를 중단해야 할 경우가 종종 발생합니다. 이번 포스팅에서는 forEach에서 반복을 중단하는 방법과 이를 대체할 수 있는 코드 패턴을 소개합니다.


🚀 forEach에서 break가 안 되는 이유

JavaScript의 forEach()는 내부적으로 콜백 함수를 실행하는 방식이기 때문에 루프를 중단할 방법이 없습니다. return을 사용해도 현재 반복만 종료할 뿐, 전체 forEach 실행은 계속됩니다.

잘못된 예제 (break 사용 불가)

const numbers = [1, 2, 3, 4, 5];

numbers.forEach((num) => {
  if (num === 3) {
    console.log('루프 중단!');
    break; // ❌ SyntaxError: Illegal break statement
  }
  console.log(num);
});

위 코드에서는 break를 사용할 수 없기 때문에 SyntaxError가 발생합니다.


✅ forEach를 중단하는 대체 방법

1️⃣ some()을 사용한 중단

some() 메서드는 특정 조건이 true가 되면 자동으로 반복을 중단합니다.

const numbers = [1, 2, 3, 4, 5];

numbers.some((num) => {
  if (num === 3) {
    console.log('루프 중단!');
    return true; // `true`를 반환하면 루프 중단
  }
  console.log(num);
  return false;
});

💡 결과

1
2
루프 중단!

some()은 특정 조건을 만족하면 루프를 중단하기 때문에 forEach 대체용으로 적합합니다.


2️⃣ every()를 사용한 중단

every()도 some()과 비슷하게 동작하지만, false를 반환하면 루프가 중단됩니다.

const numbers = [1, 2, 3, 4, 5];

numbers.every((num) => {
  if (num === 3) {
    console.log('루프 중단!');
    return false; // `false`를 반환하면 루프 중단
  }
  console.log(num);
  return true;
});

💡 결과

1
2
루프 중단!

every()는 false를 반환하면 루프를 중단하는 특징이 있습니다.


3️⃣ for...of 루프를 사용한 중단

for...of 루프는 break가 정상적으로 작동하므로 forEach를 대체할 수 있습니다.

const numbers = [1, 2, 3, 4, 5];

for (const num of numbers) {
  if (num === 3) {
    console.log('루프 중단!');
    break; // ✅ 정상 작동
  }
  console.log(num);
}

💡 결과

1
2
루프 중단!

for...of는 가독성이 좋고 break를 사용할 수 있어 forEach의 좋은 대체 방법입니다.


4️⃣ try-catch를 활용한 예외 발생 (비추천)

일부 개발자는 try-catch를 사용해 throw로 루프를 중단하는 방법을 사용하지만, 이는 성능상 좋지 않으며 예외 처리를 남용하는 방식이므로 권장하지 않습니다.

const numbers = [1, 2, 3, 4, 5];

try {
  numbers.forEach((num) => {
    if (num === 3) {
      console.log('루프 중단!');
      throw new Error('STOP_LOOP');
    }
    console.log(num);
  });
} catch (error) {
  if (error.message !== 'STOP_LOOP') throw error;
}

💡 결과

1
2
루프 중단!

이 방법은 강제적으로 forEach를 중단할 수 있지만, 예외를 활용하는 방식은 성능 저하 및 디버깅 문제를 초래할 수 있어 비추천합니다.


🎯 결론: 어떤 방법을 선택해야 할까?

방법중단 방식추천 상황

some() 사용 true 반환 시 중단 간결한 코드가 필요할 때
every() 사용 false 반환 시 중단 some()과 유사하나, 모든 요소 확인이 필요할 때
for...of 사용 break 사용 가능 가독성이 중요한 경우
try-catch 사용 throw로 강제 종료 특수한 상황에서만 사용 (비추천)

💡 가장 추천하는 방법

  • some() 또는 for...of를 활용하면 가독성이 높고 성능이 좋습니다.
  • forEach를 꼭 사용해야 하는 경우라면, some()으로 대체하는 것이 좋습니다.

🔥 최종 예제

가장 효율적인 방식인 some()과 for...of를 비교해 보겠습니다.

✅ some()을 사용한 중단:

const numbers = [1, 2, 3, 4, 5];

numbers.some((num) => {
  if (num === 3) {
    console.log('루프 중단!');
    return true;
  }
  console.log(num);
  return false;
});

 

✅ for...of를 사용한 중단:

for (const num of [1, 2, 3, 4, 5]) {
  if (num === 3) {
    console.log('루프 중단!');
    break;
  }
  console.log(num);
}

둘 다 같은 결과를 출력하지만, some()은 함수형 프로그래밍 스타일을 유지하고, for...of는 직관적이고 이해하기 쉽습니다.


✨ 마무리

  • forEach는 break를 지원하지 않음.
  • 대체 방법으로 some(), every(), for...of을 사용할 수 있음.
  • 가장 추천하는 방법은 some() (간결함) 또는 for...of (가독성).
728x90
반응형

+ Recent posts