<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Date With Data.log</title>
        <link>https://velog.io/</link>
        <description>기록 velog</description>
        <lastBuildDate>Thu, 13 Jun 2024 06:12:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Date With Data.log</title>
            <url>https://velog.velcdn.com/images/eun-woo/profile/8e97868f-30bc-4799-9d96-f84248257e3e/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Date With Data.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/eun-woo" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[오류해결과정]WSL설치 후 docker 사용 ]]></title>
            <link>https://velog.io/@eun-woo/%EC%98%A4%EB%A5%98%ED%95%B4%EA%B2%B0%EA%B3%BC%EC%A0%95WSL%EC%84%A4%EC%B9%98-%ED%9B%84-docker-%EC%82%AC%EC%9A%A9</link>
            <guid>https://velog.io/@eun-woo/%EC%98%A4%EB%A5%98%ED%95%B4%EA%B2%B0%EA%B3%BC%EC%A0%95WSL%EC%84%A4%EC%B9%98-%ED%9B%84-docker-%EC%82%AC%EC%9A%A9</guid>
            <pubDate>Thu, 13 Jun 2024 06:12:00 GMT</pubDate>
            <description><![CDATA[<p>WSL에서 도커를 사용해오다가 어느덧 다시 Ubuntu20.04를 켰을 때 갑자기 다음과 에러가 떴습니다.</p>
<blockquote>
<p>WSL2는 현재 컴퓨터 구성에서 지원되지 않습니다. &quot;가상 머신 플랫폼&quot; 선택적 구성 요소를 사용하도록 설정하고 BIOS에서 가상화가 사용하도록 설정되어 있는지 확인하세요. 실행하여 &quot;가상 머신 플랫폼&quot;을 사용하도록 설정: wsl.exe --install --no-distribution 
error code: wsl/service/createinstance/createvm/hcs/hcs_e_hyperv_not_installed</p>
</blockquote>
<p>그래서 일반적으로 WSL을 설치시의 조건을 확인해서 뭔가 빠트린게 있나 확인해보았습니다.</p>
<h3 id="1-windows-기능-켜기끄기---linux용-windows-하위-시스템-선택확인">1. Windows 기능 켜기/끄기 -&gt; Linux용 Windows 하위 시스템 선택확인</h3>
<p>(또는 cmd 관리자에서
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
명령어 )</p>
<h3 id="2-bios-cpu-가상화-기능켜기">2. BIOS CPU 가상화 기능켜기</h3>
<p>를 해보았는데도 여전히 설치 오류가 났습니다. </p>
<p>그래서 그나마 이전 Docker 컨테이너를 다 이미지로 커밋해놓았기 때문에
WSL Ubuntu를 다시 설치해야겠다고 생각했습니다. </p>
<h2 id="wsl-ubuntu2004-설치">WSL Ubuntu20.04 설치</h2>
<ol>
<li><p>PowerShell을 열고 다음과 같은 명령어를 쳐 설치된 배포판을 확인
<img src="https://velog.velcdn.com/images/eun-woo/post/254bdb4f-f0c7-4f1d-996d-13bc235276b2/image.png" alt=""></p>
</li>
<li><p>다음 명령어를 실행하여 배포판을 제거</p>
<blockquote>
<p>wsl --unregister <DistributionName></p>
</blockquote>
<ol start="3">
<li><p>제거를 완료하고 다음 명령어를 실행해 WSL을 다시 시작합니다. </p>
<blockquote>
<p>  wsl --shutdown</p>
</blockquote>
</li>
<li><p>다음 명령어를 쳐서 Ubuntu20.04를 설치합니다.</p>
<blockquote>
<p>  wsl –install -d Ubuntu20.04</p>
</blockquote>
</li>
</ol>
</li>
</ol>
<h2 id="docker-wsl에서-사용하기">Docker WSL에서 사용하기</h2>
<p>  먼저 docker desktop을 설치합니다.</p>
<p> 이후에, docker desktop의 setting에 들어간 후,
  <img src="https://velog.velcdn.com/images/eun-woo/post/c096efcd-fd62-4d2b-9e0b-895180d0880c/image.png" alt=""></p>
<p>  다음과 같이 설정을 완료합니다.</p>
<p>  그리고 docker ps 명령어를 치니 다음과 같은 오류가 떴습니다.</p>
<blockquote>
<p>  permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Head &quot;http://%2Fvar%2Frun%2Fdocker.sock/_ping&quot;: dial unix /var/run/docker.sock: connect: permission denied</p>
</blockquote>
<p>  그래서 usermod로 사용자를 docker 그룹에 추가까지 완료 후 터미널 재접속까지 했으나 permission denied 또 발생하였습니다. </p>
<p>  따라서 /var/run/docker.sock 파일의 권한을 666으로 변경하여 그룹 내 다른 사용자도 접근 가능하게 변경하였더니 
 <img src="https://velog.velcdn.com/images/eun-woo/post/ac353ef1-c97d-49e9-8b3d-474620c5ece1/image.png" alt="">
위와 같이 docker명령어가 잘 실행됨을 알 수 있었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[로그분석] on heap vs off heap]]></title>
            <link>https://velog.io/@eun-woo/%EB%A1%9C%EA%B7%B8%EB%B6%84%EC%84%9D-on-heap-vs-off-heap</link>
            <guid>https://velog.io/@eun-woo/%EB%A1%9C%EA%B7%B8%EB%B6%84%EC%84%9D-on-heap-vs-off-heap</guid>
            <pubDate>Tue, 04 Jun 2024 05:25:12 GMT</pubDate>
            <description><![CDATA[<h2 id="배경">배경</h2>
<p>Cassandra 로그분석을 하던 중, </p>
<blockquote>
<p>Writing Memtable-local@974563919(0.342KiB serialized bytes, 2 ops, 0%/0% of on/off-heap limit), flushed range = (null, null]</p>
</blockquote>
<p>위와 같은 로그가 있었다. 
여기서 Memtable은 메모리에 있는 테이블이고 <strong>974563919</strong>는 메모리 테이블의 식별자일 것이다.</p>
<p>위 로그를 한 번 뜯어보자</p>
<h2 id="memtable">Memtable</h2>
<p>Memtable은 각 Cassandra 테이블에 대해 생성된 메모리 내 캐시이다. 캐시이니 최근에 읽거나 수정한 데이터가 포함되어 있다. 따라서 노드에서 테이블의 데이터를 읽을 때마다 먼저 Memtable에 최신 데이터가 있는 지 확인한다. 최신 데이터가 없다면디스크에서 데이터를 읽고 MemTable에 캐시한다. 최대 크기, 시간 제한, 업데이트 수 등 정의된 기준이 충족되면 디스크에 flush된다. </p>
<h2 id="on-heap">On-heap</h2>
<p>on-heap은 일반적으로 자바 어플리케이션에서 객체를 생성하면 저장되는 메모리 영역(Java Heap)이다. 
GC(Garbage collector)가 관리하는 영역이기도 하며, 따라서 객체의 생성, 소멸 또한 유저가 관여를 하지 않아도 된다. 하지만 GC작업을 하는 중에는 이른바 Stop the world로 GC 쓰레드를 제외한 다른 쓰레드는 실행 중지가 되며 메모리의 큰 객체를 처리 중에는 상당히 어플리케이션 성능 저하가 심하다. </p>
<h2 id="off-heap">Off-heap</h2>
<p>Cassandra 2.1부터 offheap 메모리를 memtable에 사용할 수 있다. 
off-heap는 Heap 바깥의 (즉, GC의 관리하에 있지않다) serialized objects가 저장되는 메모리 영역이다. GC가 관리하지 않는 대신 유저가 라이브러리를 통해서 관리할 수 있다. 유저가 관리하기에 GC의 Stop the world로 인한 어플맄이션 성능 저하를 방지할 수 있다. </p>
<h2 id="로그분석">로그분석</h2>
<p>따라서 로그 분석을 하면 974563919번 2회 연산된 메모리 캐시 테이블이 0.342KiB 크기의 직렬화된 데이터를 가지고 디스크의 SSTable에 플러시했다는 것이다. 이것이 또한 off heap, on heap 최대치의 0%를 차지한다는 것이다. 즉 크기가 매우 작다는 것. 이때 (null, null]은 특정 범위가 지정되지 않아 전체 범위가 플러시 대상일 수 있다. </p>
<h3 id="출처">출처</h3>
<p><a href="https://stackoverflow.com/questions/6091615/difference-between-on-heap-and-off-heap">https://stackoverflow.com/questions/6091615/difference-between-on-heap-and-off-heap</a>
<a href="https://avdeo.com/tag/partition-summary/">https://avdeo.com/tag/partition-summary/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[방대한 로그에서 장애원인을 찾는 방법]]></title>
            <link>https://velog.io/@eun-woo/%EB%B0%A9%EB%8C%80%ED%95%9C-%EB%A1%9C%EA%B7%B8%EC%97%90%EC%84%9C-%EC%9E%A5%EC%95%A0%EC%9B%90%EC%9D%B8%EC%9D%84-%EC%B0%BE%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@eun-woo/%EB%B0%A9%EB%8C%80%ED%95%9C-%EB%A1%9C%EA%B7%B8%EC%97%90%EC%84%9C-%EC%9E%A5%EC%95%A0%EC%9B%90%EC%9D%B8%EC%9D%84-%EC%B0%BE%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sat, 11 May 2024 05:19:19 GMT</pubDate>
            <description><![CDATA[<p>이 글은 책 인프라 엔지니어의 교과서: 시스템 구축과 관리편을 토대로 작성한 글입니다. </p>
<h2 id="방대한-로그에서-원인을-찾는-노하우">방대한 로그에서 원인을 찾는 노하우</h2>
<h3 id="시각으로-범위를-좁힌다">시각으로 범위를 좁힌다.</h3>
<p>장애가 발생했을 시 장애가 발생한 시각 부근의 메시지를 확인하는 것이다. 또한 로그를 확인할 때 시스템 부하를 줄이기 위해 tail이나 head 명령을 사용해 파일의 일부만 출력하는 것도 노하우다.
*<em>다음은 리눅스 서버의 시스템 로그 파일에 대해 날짜를 지정해서 추출하는 예이다, *</em>
<img src="https://velog.velcdn.com/images/eun-woo/post/e52a363e-e387-4f25-ab92-a762ca4a19e8/image.png" alt=""></p>
<h3 id="노이즈-제거하기">노이즈 제거하기</h3>
<p>장애 발생 시각 즈음에 나타난 모든 메시지가 장애 원인은 아니다. *<em>장애 시각 즈응에 확인한 오류 메시지가 장애 발생 전부터 출력되기 시작해서 장애 발생 후에도 계속해서 출력되고 있다면 노이즈일 가능성이 크다. *</em> 이때는 grep의 -v옵션을 이용해 추출대상에서 노이즈를 제거해준다. 
<img src="https://velog.velcdn.com/images/eun-woo/post/4671fc1a-a96e-4de5-b97f-9afb0f344882/image.png" alt=""></p>
<h3 id="키워드로-범위를-좁힌다">키워드로 범위를 좁힌다.</h3>
<p>로그를 확인하는 시점에 장애 원인을 거의 추측할 수 있다면 해당 장애일 때 반드시 출력되는 문자열을 미리 알 수 있다. 이런 경우에는 해당 문자열을 바탕으로 검색하는 것이 가장 빠른 길이다. 예를 들면 아파치 오류에 대해 &quot;server reached MaxClients&quot;로 검색하면 아파치가 MaxClient에 이르렀는지 알 수 있다. </p>
<blockquote>
<p>[root@docker-centos httpd]# tail -n 1000 /var/log/httpd/error_log | grep &quot;server reached MaxClients&quot;</p>
</blockquote>
<h3 id="오류-문자열">오류 문자열</h3>
<p>오류가 발생할 때 자주 출력되는 로그 레벨 문자열을 키워드로 사용하는 게 좋다.
<img src="https://velog.velcdn.com/images/eun-woo/post/cb9583c5-b710-4f7f-8cde-9bf581337a96/image.png" alt="">
이 때 waring은 WARN으로도 쓰일 수 있고 warning으로 쓰일수도 있다. 따라서 검색 시 대소문자를 구별하지 않게 하기 위해 grep의 -i 옵션을 사용할 수 있다. </p>
<blockquote>
<p>[root@docker-centos httpd]# tail -n 1000 /var/log/hoge/applications.log | grep -i &quot;warn&quot;</p>
</blockquote>
<h3 id="메시지-양을-주목">메시지 양을 주목</h3>
<p>오류 메시지에는 아무것도 출력되지 않았는데 사이트가 보이지 않거나 메일이 전송되지 않는 등 서비스에 문제가 생기는 경우가 있다. 이런 경우는 요청 대비 시스템의 처리 성능이 뒷받침하지 못하는 것이 원인이다. 시각별로 엑세스 로그를 집계해보자.</p>
<blockquote>
<p>[root@docker-centos httpd]# tail -n 10000 access_log | grep &quot;May&quot; | cut -d &#39;:&#39; -f 2,3 | sort | uniq -c</p>
</blockquote>
<p>여기서 &quot;cut -d &#39;:&#39; -f 2,3&quot;은 :를 기준으로 2, 3번째 필드를 추출하고 uniq -c는 중복을 카운팅하여 제거해서 출력하라는 것을 뜻한다.</p>
<p>엑세스한 소스 IP 주소별로 집계하면 어떤 IP 주소에서 엑세스가 많았는 지 알 수 있다. 특정 IP 주소의 접속이 극단적으로 많으면 부정 엑세스나 검색 엔진 로봇에 의한 스캔일수도 있다. </p>
<blockquote>
<p>[root@docker-centos httpd]# tail -n 10000 access_log | grep &quot;May&quot; | awk &#39;{print $1}&#39; | sort -n | uniq -c | sort</p>
</blockquote>
<p>하지만 메시지 양을 비교하는 방법은 신중하게 해야한다. 할인판매 같이 엑세스 양이 무척이나 많은 날일수도 있기에 엑세스가 많은 날인지 고려해서 사용해야한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[이상(Anamoly)을 나타내는 로그 패턴유형]]></title>
            <link>https://velog.io/@eun-woo/%EC%9D%B4%EC%83%81Anamoly%EC%9D%84-%EB%82%98%ED%83%80%EB%82%B4%EB%8A%94-%EB%A1%9C%EA%B7%B8-%ED%8C%A8%ED%84%B4%EC%9C%A0%ED%98%95</link>
            <guid>https://velog.io/@eun-woo/%EC%9D%B4%EC%83%81Anamoly%EC%9D%84-%EB%82%98%ED%83%80%EB%82%B4%EB%8A%94-%EB%A1%9C%EA%B7%B8-%ED%8C%A8%ED%84%B4%EC%9C%A0%ED%98%95</guid>
            <pubDate>Fri, 10 May 2024 09:13:21 GMT</pubDate>
            <description><![CDATA[<p>출처: Zhao, Nengwen, et al. &quot;An empirical investigation of practical log anomaly detection for online service systems.&quot; Proceedings of the 29th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering. 2021. </p>
<h2 id="6가지-일반적인-비정상-패턴">6가지 일반적인 비정상 패턴</h2>
<h3 id="키워드">키워드</h3>
<p>일부 부정 키워드(Ex: &quot;OutOfMemory&quot;)가 로그 메시지에 나타나면 이 로그는 비정상</p>
<h3 id="로그-템플릿-수">로그 템플릿 수</h3>
<p>일부 템플릿의 수는 크게 증가하거나 감소</p>
<h3 id="로그-템플릿-시퀀스">로그 템플릿 시퀀스</h3>
<p>일반적인 정상 패턴에서는 로그 템플릿 시퀀스가 A-&gt;B-&gt;C로 나타나는데, A-&gt;C-&gt;B 등 순서가 바뀜을 확인했다면 시스템의 이상을 의심해볼 수 있음. </p>
<h3 id="변수-값">변수 값</h3>
<p>로그의 특정 변수에는 시간비용과 같은 물리적의미가 있으며, 이를 추출하여 시계열 형식의 메트릭으로 집계가 가능하다. 여기서 나온 메트릭에서 이상을 식별할 수 있다.</p>
<h3 id="변수-분포">변수 분포</h3>
<p>예를 들어, Nginx 엑세스 로그에는 Ip 주소나 Http상태 코드 정보가 들어있다. 예를 들어, Http 상태코드에서 502에 많이 치우치면 시스템 이상, 특정 IP주소에서의 요청이 급격하게 많다면 보안상 공격을 의심해볼 수 있다. </p>
<h3 id="시간-간격">시간 간격</h3>
<p>네트워크 정체 등의 성능문제로 인해 로그 간 시간간격 (timestamp 간격)이 길어질 수 있다. 또한 시간 간격 이상이 템플릿 수 이상의 결과를 초래할 수도 있다.</p>
<h2 id="이상-패턴과-시스템-이상-시나리오">이상 패턴과 시스템 이상 시나리오</h2>
<p>다음은 일반적으로 많이 사용되는 어플리케이션, OS, DB, HW, JVM GC등의 로그파일에서 나올 수 있는 이상 패턴과 시스템 이상 시나리오다.</p>
<h3 id="applicationapplication-error">Application(Application error)</h3>
<h4 id="이상-패턴">이상 패턴</h4>
<p>템플릿 수 변화(ex: &quot;connection refused&quot; 증가), 이전에 없던 로그 패턴(unknown error messages)</p>
<h4 id="이상사고-시나리오">이상(사고) 시나리오</h4>
<p>System unavailability, application error</p>
<h3 id="operation-systemlinux-windows-aix">Operation System(Linux, Windows, AIX..)</h3>
<h4 id="이상-패턴-1">이상 패턴</h4>
<p>키워드(ex: &quot;soft lockup&quot;, &quot;page allocation failure&quot;)
총 로그 수, 템플릿 수 변화(ex: &quot;creatin session&quot; 감소)</p>
<h4 id="이상사고-시나리오-1">이상(사고) 시나리오</h4>
<p>Out of Memory, node hang, hardware failures</p>
<h3 id="databaseoracle-db2-mysql-">DataBase(Oracle, DB2, MySQL ..)</h3>
<h4 id="이상패턴">이상패턴</h4>
<p>키워드(ex: &quot;ORA-&quot;, &quot;Level: Error&quot;), 새로운 로그 패턴</p>
<h4 id="이상사고-시나리오-2">이상(사고) 시나리오</h4>
<p>DB 서버 다운, 성능 저하, SQL defect</p>
<h3 id="하드웨어switch-f5-네트워크-디바이스-등">하드웨어(Switch, F5 네트워크 디바이스 등)</h3>
<h4 id="이상패턴-1">이상패턴</h4>
<p>키워드(ex: &quot;Illegal state transition&quot;, &quot;address conflict detected&quot;), 새로운 로그 패턴, 로그 템플릿 수 변화</p>
<h4 id="이상사고-시나리오-3">이상(사고) 시나리오</h4>
<p>IP address 충돌</p>
<h3 id="분산시스템hdfs-openstack">분산시스템(HDFS, OpenStack)</h3>
<h4 id="이상패턴-2">이상패턴</h4>
<p>키워드(ex: &quot;IOException&quot;), 템플릿 시퀀스 이상(wrong order of execution), 새로운 로그 패턴</p>
<h4 id="이상사고-시나리오-4">이상(사고) 시나리오</h4>
<p>Task failed, instance failure</p>
<h3 id="operation유저-행동">Operation(유저 행동)</h3>
<h4 id="이상패턴-3">이상패턴</h4>
<p>템플릿 수 변화, 템플릿 시퀀스 이상</p>
<h4 id="이상사고-시나리오-5">이상(사고) 시나리오</h4>
<p>Illegal operation, security issue</p>
<h3 id="middlewareweb-server-ex-nginx-acess-apache-access">Middleware(Web server ex: Nginx acess, Apache Access)</h3>
<h4 id="이상패턴-4">이상패턴</h4>
<p>변수 분포 이상(ex: &quot;return code, IP address 치중), 총 로그 수 변화</p>
<h4 id="이상사고-시나리오-6">이상(사고) 시나리오</h4>
<p>System unavailability, illegal user access, security threat</p>
<h3 id="미들웨어jvm-gc">미들웨어(JVM GC)</h3>
<h4 id="이상패턴-5">이상패턴</h4>
<p>키워드(ex: &quot;OutofMemory&quot;), 로그 템플릿 수 변화(&quot;FullGC&quot; 수 증가), valiable value(GC time cost 이상)</p>
<h4 id="이상사고-시나리오-7">이상(사고) 시나리오</h4>
<p>GC overhead limit exceeded, full heap space, memory leak</p>
<h3 id="미들웨어메시지-큐-ex-ibm-mq">미들웨어(메시지 큐 ex: IBM MQ)</h3>
<h4 id="이상패턴-6">이상패턴</h4>
<p>키워드(ex: &quot;error occur&quot;, &quot;ended abnormally&quot;, &quot;exception&quot;), 새로운 로그 패턴, 로그 템플릿 수 변화</p>
<h4 id="이상사고-시나리오-8">이상(사고) 시나리오</h4>
<p>message queue stuck</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[아파치 httpd 시작 시 오류 해결]]></title>
            <link>https://velog.io/@eun-woo/%EC%95%84%ED%8C%8C%EC%B9%98-httpd-%EC%8B%9C%EC%9E%91-%EC%8B%9C-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0</link>
            <guid>https://velog.io/@eun-woo/%EC%95%84%ED%8C%8C%EC%B9%98-httpd-%EC%8B%9C%EC%9E%91-%EC%8B%9C-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0</guid>
            <pubDate>Mon, 06 May 2024 14:54:55 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>[root@docker-centos httpd]# systemctl restart httpd
Job for httpd.service failed because the control process exited with error code. See &quot;systemctl status httpd.service&quot; and &quot;journalctl -xe&quot; for details.</p>
</blockquote>
<p>다음과 같이 httpd를 시작하려고 하니 에러가 났다. </p>
<p>/var/log/messages 로 로그를 확인해보았더니, 다음과 같은 내용을 확인할 수 있었다. </p>
<blockquote>
<p>May 06 23:27:28 docker-centos.example.com systemd[1]: Starting The Apache HTTP Server...
May 06 23:27:28 docker-centos.example.com httpd[10936]: (98)Address already in use: AH00072: make_sock: could not bind to address [::]:80
May 06 23:27:28 docker-centos.example.com httpd[10936]: (98)Address already in use: AH00072: make_sock: could not bind to address 0.0.0.0:80
May 06 23:27:28 docker-centos.example.com httpd[10936]: no listening sockets available, shutting down
May 06 23:27:28 docker-centos.example.com httpd[10936]: AH00015: Unable to open logs
May 06 23:27:28 docker-centos.example.com systemd[1]: httpd.service: main process exited, code=exited, status=1/FAILURE
May 06 23:27:28 docker-centos.example.com systemd[1]: Failed to start The Apache HTTP Server.
May 06 23:27:28 docker-centos.example.com systemd[1]: Unit httpd.service entered failed state.
May 06 23:27:28 docker-centos.example.com systemd[1]: httpd.service failed.</p>
</blockquote>
<p>address가 이미 사용되고 있었다는 오류였다. </p>
<ol>
<li><p>일단 먼저 실행중인 httd 프로세스를 모두 강제 종료 시킨다.</p>
<blockquote>
<p>[root@docker-centos httpd]# ps ax | grep httpd | awk &#39;{print $1}&#39; | xargs kill</p>
</blockquote>
</li>
<li><p>그 다음에는 80번 포트 사용하고 있는 pid를 확인한다.</p>
<blockquote>
<p>[root@docker-centos httpd]# netstat -nlp | grep 80
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      8572/nginx: master</p>
</blockquote>
</li>
</ol>
<p>n은 호스트 이름과 서비스 이름 대신 IP 주소와 포트 번호를 표시하도록 하고, l은 리스닝하고 있는 소켓을 보여준다. -p는 해당 포트를 사용 중인 프로세스의 PID와 프로그램 이름을 표시한다.</p>
<ol start="3">
<li><p>그 프로세스를 종료한다.</p>
<blockquote>
<p>kill -9 (프로세스 아이디)</p>
</blockquote>
</li>
<li><p>httpd 재시작한다. 성공.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[컨테이너가 뭐고 왜 쓸까?]]></title>
            <link>https://velog.io/@eun-woo/%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88%EA%B0%80-%EB%AD%90%EA%B3%A0-%EC%99%9C-%EC%93%B8%EA%B9%8C</link>
            <guid>https://velog.io/@eun-woo/%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88%EA%B0%80-%EB%AD%90%EA%B3%A0-%EC%99%9C-%EC%93%B8%EA%B9%8C</guid>
            <pubDate>Sun, 28 Apr 2024 03:22:43 GMT</pubDate>
            <description><![CDATA[<p><strong>이 글은 이성미 강사의 따배도 강의를 보고 작성한 글입니다.</strong></p>
<h2 id="배경">배경</h2>
<p><img src="https://velog.velcdn.com/images/eun-woo/post/b87870c6-8541-46e0-a4cd-f34294488785/image.png" alt="">
출처: <a href="https://itwiki.kr/w/%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88_%EA%B0%80%EC%83%81%ED%99%94">https://itwiki.kr/w/%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88_%EA%B0%80%EC%83%81%ED%99%94</a></p>
<h4 id="전통적인-단일-환경">전통적인 단일 환경</h4>
<p>과거에는 BareMetal의 하나의 시스템에 여러가지 어플리케이션을 운영하다가, 점차 하드웨어 가격이 작아지고, 성능은 좋아지고, 운영해야할 어플리케이션은 많아져 가상화 플랫폼으로 옮겨지게 되었다. </p>
<h4 id="가상화-플랫폼">가상화 플랫폼</h4>
<p>가상화 플랫폼에서는 Hypervisor위로 가상 운영체제를 설치하고 그 위에 어플리케이션을 올리게 되었다. 그런데 이 가상환경 위에 운영해야하는 어플리케이션이 많아지면서, 이러한 가상환경 플랫폼으로는 한계가 생기게 되었다. </p>
<h4 id="컨테이너-플랫폼">컨테이너 플랫폼</h4>
<p>그래서 나타난게 컨테이너 플랫폼이다. 컨테이너로 운영되는 어플리케이션은 용량이 작다. 실제 어플리케이션과 그걸 실행할 수 있는 최소한의 환경만 들어가 있기 때문이다. </p>
<p>그리고 isolated되어있고, 확장성이 좋다. </p>
<p>APP과 그걸 실행하기 위한 라이브러리 또는 NodeJS같은 환경을 컨테이너에 넣는다. </p>
<h2 id="왜-굳이-리눅스에서-돌려야-할까">왜 굳이 리눅스에서 돌려야 할까?</h2>
<p>*<em>=&gt;리눅스 커널 기능을 써야 하기 때문이다. *</em></p>
<h4 id="chroot">chroot</h4>
<p>독립된 공간 형성</p>
<h4 id="namespace">namespace:</h4>
<p>Isolate 기능 지원: 하나의 컨테이너와 하나의 다른 컨테이너가 완전히 독립될 수 있도록 한다. </p>
<h4 id="cgroup">cgroup</h4>
<p>필요한만큼 HW를 지원해준다.</p>
<p>이 기능들은 모두 리눅스 커널에 있다. 이 리눅스 커널에 있는 기능을 기반으로 해서 컨테이너를 만든다. </p>
<p>windows와 Mac OS는 커널이 없기에 Hypervisor 기능들을 활성화 해야 컨테이너를 돌릴 수 있게 된다. </p>
<h2 id="그냥-프로그램과-컨테이너는-뭐가-다를까">그냥 프로그램과 컨테이너는 뭐가 다를까?</h2>
<p>일반 프로그램: 서버 프로그램인 app.js가 있다. 이것은 nodeJS기반에서 동작하므로 이 서버 프로그램을 실행하기 위해서는 그 전에 먼저 nodeJS를 설치해야한다. </p>
<p>컨테이너: dockerfile을 통해 nodeJS와 app.js를 가지고 컨테이너 빌드한다. 이 컨테이너를 실행하면 자동으로 서버 플로그램을 실행한다. </p>
<h2 id="그래서-왜-쓸까">그래서 왜 쓸까?</h2>
<p>*<em>개발자가 만든 그대로 어시서든 돌아간다.
확장/축소가 쉽고, MSA, DEVOPS에 적합하다. *</em></p>
<p>개발자가 application container를 만들면 A고객사에 제공을 한다. 고객사는 원래 개발자가 어플을 만들 때 사용한 환경과 다르기에 고객사의 환경에서 어플을 돌린거와 결과가 다를 수 있다. 하지만 컨테이너 기반으로 만들어서 제공을 하면 컨테이너를 돌리면 같은 결과가 나온다. <strong>즉, 환경에 구애받지 않는다.</strong></p>
<p>또한, 컨테이너의 용량이 100MB라고 하자. scale-out을 하고 싶으면 그저 컨테이너를 하나 더 설치하면 되는 것이다. 그러면 200MB가 소요되는 것이다. 즉, 확장 축소에 매우 유리하다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[쿠버네티스]Errno 14] HTTPS Error 404 - Not Found 패키지를 못찾을 때
]]></title>
            <link>https://velog.io/@eun-woo/%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4Errno-14-HTTPS-Error-404-Not-Found-%ED%8C%A8%ED%82%A4%EC%A7%80%EB%A5%BC-%EB%AA%BB%EC%B0%BE%EC%9D%84-%EB%95%8C</link>
            <guid>https://velog.io/@eun-woo/%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4Errno-14-HTTPS-Error-404-Not-Found-%ED%8C%A8%ED%82%A4%EC%A7%80%EB%A5%BC-%EB%AA%BB%EC%B0%BE%EC%9D%84-%EB%95%8C</guid>
            <pubDate>Sat, 27 Apr 2024 10:08:26 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes</p>
</blockquote>
<p>이 명령어를 쳤더니 </p>
<blockquote>
<p><a href="https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64/repodata/repomd.xml">https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64/repodata/repomd.xml</a>: [Errno 14] HTTPS Error 404 - Not Found</p>
</blockquote>
<p>이 에러가 떴다. 패키지를 못찾는다는 에러가 떠서 정보를 찾던 중,  <a href="https://www.inflearn.com/news/1198141">https://www.inflearn.com/news/1198141</a> 이런 글을 발견했다. 
구글에서 해당 repository를 지원하지 않는다는 것이다. </p>
<p>쿠버네티스의 공식홈페이지의 <a href="https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/">https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/</a>
에서 해결법을 찾을 수 있었다. 역시 공식문서의 힘은 대단하다고 생각했다. </p>
<p>공식문서대로 
cat &lt;&lt;EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=<a href="https://pkgs.k8s.io/core:/stable:/v1.30/rpm/">https://pkgs.k8s.io/core:/stable:/v1.30/rpm/</a>
enabled=1
gpgcheck=1
gpgkey=<a href="https://pkgs.k8s.io/core:/stable:/v1.30/rpm/repodata/repomd.xml.key">https://pkgs.k8s.io/core:/stable:/v1.30/rpm/repodata/repomd.xml.key</a>
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
EOF
로 정보를 kubernetes.repo를 수정했더니 해결되었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[오류해결]==== AUTHENTICATING FOR org.freedesktop.systemd1.reload-daemon ===
뜰 때
]]></title>
            <link>https://velog.io/@eun-woo/%EC%98%A4%EB%A5%98%ED%95%B4%EA%B2%B0-AUTHENTICATING-FOR-org.freedesktop.systemd1.reload-daemon-%EB%9C%B0-%EB%95%8C</link>
            <guid>https://velog.io/@eun-woo/%EC%98%A4%EB%A5%98%ED%95%B4%EA%B2%B0-AUTHENTICATING-FOR-org.freedesktop.systemd1.reload-daemon-%EB%9C%B0-%EB%95%8C</guid>
            <pubDate>Fri, 26 Apr 2024 11:47:48 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>==== AUTHENTICATING FOR org.freedesktop.systemd1.reload-daemon ===
Authentication is required to reload the systemd state.
Authenticating as: root
Password:</p>
</blockquote>
<p>라고 systemctl명령어를 쓸 때, 이런 오류가 뜰 때가 있다.</p>
<p> 해결법은 간단하다 </p>
<p> 관리자 전용의 권한이므로 당연히 상위 권한 요구하게 된다.
미리 권한 부여해두던지 안 하면 무조건 비번 묻게 된다. (계정이 서비스 관리 권한을 안 가진한)</p>
<p><strong>sudo --를 사용하던가 root로 접속해서 실행하면 된다.</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[리눅스]Swap, /etc/fstab]]></title>
            <link>https://velog.io/@eun-woo/%EB%A6%AC%EB%88%85%EC%8A%A4Swap-etcfstab</link>
            <guid>https://velog.io/@eun-woo/%EB%A6%AC%EB%88%85%EC%8A%A4Swap-etcfstab</guid>
            <pubDate>Thu, 25 Apr 2024 03:01:54 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>sed -i.bak -r &#39;s/(.+ swap .+)/#\1/&#39; /etc/fstab</p>
</blockquote>
<p>위 명령어를 실행시키면 /etc/fstab에서 swap부분이 있는 줄을 전체 주석처리한다. 주석처리하면 무슨일이 벌어질까?</p>
<h3 id="etcfstab">/etc/fstab</h3>
<p>/etc/fstab을 열어보니 다음과 같은 줄이 있었다.</p>
<blockquote>
<p>/dev/mapper/centos_k8s-swap swap                    swap    defaults        0 0</p>
</blockquote>
<p> /dev/mapper/centos_k8s-swap은 스왑 파티션을 나타내는 장치의 경로이다. swap은 파일 시스템 유형을 나타내며, defaults는 기본 마운트 옵션을 나타낸다. 마지막 두 열은 보통 시스템 백업과 파일 시스템 체크에 사용되는 것으로, 스왑 파티션에는 보통 0이나 비어있는 값이 사용된다.</p>
<h3 id="주석처리하면-어떻게-될까">주석처리하면 어떻게 될까?</h3>
<p>위의 /dev/mapper/centos_k8s-swap swap swap defaults 0 0 라인을 주석 처리하면, 시스템이 해당 스왑 파티션을 인식하지 않게 된다. 시스템 부팅할때 스왑 파티션을 마운트하지 않으며, 따라서 *<em>해당 스왑 공간을 사용할 수 없게 된다. *</em></p>
<p>다만 스왑 파티션은 시스템이 컴퓨터의 메모리를 다 썼을 때, 여분 공간을 만들어서 쓰는 것이므로 이것을 주석처리하면 시스템 메모리 부족 현상에서 문제를 느낄 수 있으니 주의해서 서야한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[환경설정 쉘스크립트]]></title>
            <link>https://velog.io/@eun-woo/%ED%99%98%EA%B2%BD%EC%84%A4%EC%A0%95-%EC%89%98%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8</link>
            <guid>https://velog.io/@eun-woo/%ED%99%98%EA%B2%BD%EC%84%A4%EC%A0%95-%EC%89%98%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8</guid>
            <pubDate>Thu, 25 Apr 2024 02:22:30 GMT</pubDate>
            <description><![CDATA[<h2 id="환경설정-쉘스크립트">환경설정 쉘스크립트</h2>
<p><img src="https://velog.velcdn.com/images/eun-woo/post/b3e874cd-4532-41f6-9eb4-2339853b81a1/image.png" alt="">
표 출처 : <a href="https://blog.naver.com/PostView.nhn?blogId=sdrock&amp;logNo=221508545540">https://blog.naver.com/PostView.nhn?blogId=sdrock&amp;logNo=221508545540</a></p>
<p>리눅스에 로그인을 하면 자동으로 쉘 스크립트가 실행된다. 이것을 <strong>환경설정 쉘스크립트</strong>라고 한다. 
위의 표는 환경설정 쉘스크립트인데 적용되는 범위가 다르다.</p>
<p>일반적으로 리눅스에 접속을 하면 
/etc/profile -&gt; ~./bash_profile -&gt; ~/.bashrc -&gt; 로그인 쉘 프롬프트 순으로 켜진다.</p>
<p>가령
vagrantfile의 설정파일 config.sh에 </p>
<blockquote>
<p>echo &#39;alias vi=vim&#39; &gt;&gt; /etc/profile</p>
</blockquote>
<p>이라는 내용을 작성해두면 vagrant up으로 프로비저닝 후, 자동으로 위의 alias가 적용되어 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[오류해결]yum실행 시Could not retrieve mirrorlist...에러]]></title>
            <link>https://velog.io/@eun-woo/%EC%98%A4%EB%A5%98%ED%95%B4%EA%B2%B0yum%EC%8B%A4%ED%96%89-%EC%8B%9CCould-not-retrieve-mirrorlist...%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@eun-woo/%EC%98%A4%EB%A5%98%ED%95%B4%EA%B2%B0yum%EC%8B%A4%ED%96%89-%EC%8B%9CCould-not-retrieve-mirrorlist...%EC%97%90%EB%9F%AC</guid>
            <pubDate>Fri, 19 Apr 2024 14:24:01 GMT</pubDate>
            <description><![CDATA[<p>vagrant로 CentOS 가상환경을 구축하고, 다음과 같이 vagrantfile에 부팅할때마다 쉘을 실행한다는 내용을 작성했다. </p>
<blockquote>
<p>cfg.vm.provision &quot;shell&quot;, path: &quot;install_pkg.sh&quot;</p>
</blockquote>
<p>쉘의 내용은 다음과 같다.</p>
<h4 id="install_pkgsh">install_pkg.sh</h4>
<blockquote>
<p>#!/usr/bin/env bash
#install packages
yum install epel-release -y
yum install vim-enhanced -y</p>
</blockquote>
<p>그랬더니 </p>
<blockquote>
<p>Could not retrieve mirrorlist <a href="http://mirrorlist.centos.org/?release=7&amp;arch=x86_64&amp;repo=os&amp;infra=stock">http://mirrorlist.centos.org/?release=7&amp;arch=x86_64&amp;repo=os&amp;infra=stock</a> error was
14: curl#6 - &quot;Could not resolve host: mirrorlist.centos.org; Unknown error&quot;</p>
</blockquote>
<p>다음과 같은 에러가 떴다.</p>
<h3 id="문제-분석">문제 분석</h3>
<p>mirrorlist.centos.org 서버에 resolve할 수가 없다는 내용이다.
나는 다음의 2개의 문제가 있다고 생각했다.</p>
<h4 id="1-mirrorlistcentosorg-사이트에-문제가-없어-응답을-받아올-수-없다">1. mirrorlist.centos.org 사이트에 문제가 없어 응답을 받아올 수 없다</h4>
<h4 id="2-mirrorlistcentosorg-ip에-도달-할-수가-없다">2. mirrorlist.centos.org IP에 도달 할 수가 없다</h4>
<p>나는 2번이 더 가능성이 높다고 생각했고, DNS 서버 주소가 등록이 안되어있나라고 생각했다.</p>
<h3 id="문제-해결">문제 해결</h3>
<blockquote>
<p>$ sudo vi /etc/resolv.conf</p>
</blockquote>
<p>로 들어가서 DNS서버 주소가 등록되어있는 지 확인해보았다. 
nameserver 10.0.2.3이 등록되어있었고, </p>
<blockquote>
<p>ping 10.0.2.3</p>
</blockquote>
<p>이렇게 핑 테스트를 하니 응답을 전혀 받을 수 없었다.
<strong>따라서 등록되어있는 DNS에게는 요청을 받을 수 없는 상태다.</strong>
그래서 새로 구글 DNS를 등록하고 다시 프로비저닝 시키니 잘 작동했다.</p>
<blockquote>
<p>nameserver 10.0.2.3</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[vagrant]stderr: vboxmanage.exe: error: failed to get device handle...]]></title>
            <link>https://velog.io/@eun-woo/%EC%97%90%EB%9F%AC%ED%95%B4%EA%B2%B0stderr-vboxmanage.exe-error-failed-to-get-device-handle</link>
            <guid>https://velog.io/@eun-woo/%EC%97%90%EB%9F%AC%ED%95%B4%EA%B2%B0stderr-vboxmanage.exe-error-failed-to-get-device-handle</guid>
            <pubDate>Thu, 18 Apr 2024 01:17:14 GMT</pubDate>
            <description><![CDATA[<p>vagrant에서 가상머신을 실행시기 위해</p>
<blockquote>
<p>vagrant up</p>
</blockquote>
<p>을 실행시켰더니 </p>
<blockquote>
<p>stderr: vboxmanage.exe: error: failed to get device handle and/or partition id for 0000000001ed7590 (hpartitiondevice=0000000000000a7d, last=0xc0000002/1) (verr_nem_vm_create_failed) vboxmanage.exe: error: details: code e_fail (0x80004005), component consolewrap, interface iconsole</p>
</blockquote>
<p>이러한 에러가 떴다.</p>
<h2 id="해결법">해결법</h2>
<p>cmd를 관리자 권한으로 실행한 뒤,</p>
<blockquote>
<p>bcedit</p>
</blockquote>
<p>를 실행한다.</p>
<p>여기서 hypervisorlaunchtype이 Auto로 되어있다면</p>
<blockquote>
<p>bcedit /set hypervisorlaunchtype off</p>
</blockquote>
<p>로 off로 바꿔주고 재부팅한 후, vagrant up을 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[root 권한이 없는 sudo 명령어(is not in the sudoers file. This incident will be reported.)]]></title>
            <link>https://velog.io/@eun-woo/root-%EA%B6%8C%ED%95%9C%EC%9D%B4-%EC%97%86%EB%8A%94-sudo-%EB%AA%85%EB%A0%B9%EC%96%B4is-not-in-the-sudoers-file.-This-incident-will-be-reported</link>
            <guid>https://velog.io/@eun-woo/root-%EA%B6%8C%ED%95%9C%EC%9D%B4-%EC%97%86%EB%8A%94-sudo-%EB%AA%85%EB%A0%B9%EC%96%B4is-not-in-the-sudoers-file.-This-incident-will-be-reported</guid>
            <pubDate>Tue, 16 Apr 2024 14:44:50 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>사용자명 is not in the sudoers file. This incident will be reported.</p>
</blockquote>
<p>sudo 명령어를 쳤을 때, 위와 같은 에러가 나는 경우가 있다.</p>
<p>이것은 <strong>현재 사용자가 sudo 권한이 없다는 뜻이다.</strong></p>
<h3 id="해결방법">해결방법</h3>
<blockquote>
<p>su</p>
</blockquote>
<p>명령어를 쳐서 root계정으로 들어간다.</p>
<blockquote>
<p>$ vi /etc/sudoers</p>
</blockquote>
<p>위와 같이 파일을 들어간다. 그리고 파일에는 다음과 같은 내용이 있다. </p>
<blockquote>
<p>root ALL=(ALL) ALL</p>
</blockquote>
<p>위와 같은 부분 아래에 </p>
<blockquote>
<p>사용자명 ALL=(ALL) ALL</p>
</blockquote>
<p>을 입력하고 저장한다.</p>
<p>다만, 그냥 vi로는 readonly로 적용되니 </p>
<blockquote>
<p>visudo -f /etc/sudoers</p>
</blockquote>
<p>명령어를 통해 들어간다. </p>
<p>만약 sudo 명령어를 칠때 password를 적용하고 싶지 않다면, </p>
<blockquote>
<p>사용자명 ALL=(ALL) NOPASSWD:ALL를 사용하면 된다.</p>
</blockquote>
<p>특정 명령어만을 sudo 권한을 주고 싶다면, 그렇게 하는 방법도 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[스프링 시큐리티]authenticate처리하는 과정을 살펴보자]]></title>
            <link>https://velog.io/@eun-woo/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0authenticate%EC%B2%98%EB%A6%AC%ED%95%98%EB%8A%94-%EA%B3%BC%EC%A0%95%EC%9D%84-%EC%82%B4%ED%8E%B4%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@eun-woo/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0authenticate%EC%B2%98%EB%A6%AC%ED%95%98%EB%8A%94-%EA%B3%BC%EC%A0%95%EC%9D%84-%EC%82%B4%ED%8E%B4%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Sun, 07 Apr 2024 15:15:54 GMT</pubDate>
            <description><![CDATA[<p><strong>authenticate(인증)처리는 인증 필터에서 수행되는데, 크게 로그인 인증처리하는 attemptAuthentication메소드와 인증 성공 후 처리하는 succesfulAtuthentication메소드를 거쳐 수행된다.</strong></p>
<h2 id="로그인-인증처리하는-attemptauthenticationreq-res">로그인 인증처리하는 attemptAuthentication(req, res)</h2>
<h3 id="authenticate하는-주체">Authenticate하는 주체</h3>
<pre><code>@Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
            throws AuthenticationException {
        try {

            RequestLogin creds = new ObjectMapper().readValue(req.getInputStream(), RequestLogin.class);
            //authenticationManager가 id와 pw를 바교해줌
            return getAuthenticationManager().authenticate(
                    new UsernamePasswordAuthenticationToken(creds.getEmail(), creds.getPassword(), new ArrayList&lt;&gt;()));

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }</code></pre><p>authenticate()는 인증 필터에서 로그인 인증을 처리하는 부분 attemptAuthentication에 적용된다. 코드에서 알 수 있듯이 authenticate하는 주체는 <strong>AuthenticationManager</strong>이다.<br>authenticationManager는 구현체인 providerManager가 각각의 인증을 실질적으로 처리하는 AuthenticationProvider를 찾는다. </p>
<h3 id="authenticate메소드의-처리과정">authenticate()메소드의 처리과정</h3>
<p><strong>ID검증</strong>: UserDetailsService에서 DB에서 사용자를 조회. 사용자가 없을 경우 UserNotFoundException 예외를 발생시킨다. 성공하면 UserDetails 객체를 반환한다.
(select pwd from users where email=?)</p>
<p><strong>Password 검증</strong>: 반환 받은 UserDetails 객체에 저장된 Password와 Authentication에 저장된 Password(로그인시 입력한 Password)를 matches 메서드를 이용하여 비교. 일치하지 않는다면 BadCredentialException 예외를 발생시킨다.
(passencoder로 login정보에서 패스워드 암호화함)</p>
<p>추가 검증 까지 완료하면 Authentication(유저 정보, 권한 정보)를 AuthenticationManager에게 전달. AuthenticationManager는 Filter에게 전달하고, Filter는 이 정보를 전역적으로 사용할 수 있게 <strong>SecurityContext에 전달한다</strong>.(그래서 attemptAuthentication의 리턴값이 Aithentication이다.)</p>
<h4 id="authentication-클래스는-다음과-같다">Authentication 클래스는 다음과 같다</h4>
<pre><code>public interface Authentication extends Principal, Serializable {
    Collection&lt;? extends GrantedAuthority&gt; getAuthorities();

    Object getCredentials();

    Object getDetails(); -&gt;

    Object getPrincipal();

    boolean isAuthenticated(); // 인증되면 true로 변함</code></pre><p>그렇게 Filter에게 반환한 Authentication 객체는 다음과 같이 jwt토큰을 만들고 response에 넣기 위해 다음의 메소드의 인자로 들어간다.</p>
<pre><code>@Override
    protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
                                            Authentication auth) throws IOException, ServletException {
        String userName = ((User) auth.getPrincipal()).getUsername();
        UserDto userDetails = userService.getUserDetailsByEmail(userName);
        //토큰 생성
        byte[] secretKeyBytes = Base64.getEncoder().encode(environment.getProperty(&quot;token.secret&quot;).getBytes());

        SecretKey secretKey = Keys.hmacShaKeyFor(secretKeyBytes);

        Instant now = Instant.now();

        String token = Jwts.builder()
                .subject(userDetails.getUserId())
                .expiration(Date.from(now.plusMillis(Long.parseLong(environment.getProperty(&quot;token.expiration_time&quot;)))))
                .issuedAt(Date.from(now))
                .signWith(secretKey)
                .compact();

        res.addHeader(&quot;token&quot;, token);
        res.addHeader(&quot;userId&quot;, userDetails.getUserId());

    }</code></pre><p>authentication 객체에서 userName(email)을 추출한다. 이 정보를 가지고 나중에 인가에 사용될 userId 등을 추출한다. </p>
<h2 id="jwt-토큰-만들기">JWT 토큰 만들기</h2>
<p><img src="https://velog.velcdn.com/images/eun-woo/post/7e965575-3f39-46fa-823c-6347c372de8b/image.png" alt=""></p>
<p>위 그림은 실제 jwt토큰값을 디코딩한 사진이다. 
jwt토큰은 </p>
<h4 id="header암호-알고리즘payloaduserid-토큰만기env-설정값secret-keyenv-설정값"><strong>Header(암호 알고리즘).Payload(userId, 토큰만기(env 설정값)).secret key(env 설정값)</strong></h4>
<p>을 암호화시킨다.</p>
<p>그리고 이것을 response 정보에다가 userId, 토큰값을 헤더에 추가한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[스프링 시큐리티]토큰 추가시에도 403 Forbidden이 뜨는 경우]]></title>
            <link>https://velog.io/@eun-woo/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0%ED%86%A0%ED%81%B0-%EC%B6%94%EA%B0%80%EC%8B%9C%EC%97%90%EB%8F%84-403-Forbidden%EC%9D%B4-%EB%9C%A8%EB%8A%94-%EA%B2%BD%EC%9A%B0</link>
            <guid>https://velog.io/@eun-woo/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0%ED%86%A0%ED%81%B0-%EC%B6%94%EA%B0%80%EC%8B%9C%EC%97%90%EB%8F%84-403-Forbidden%EC%9D%B4-%EB%9C%A8%EB%8A%94-%EA%B2%BD%EC%9A%B0</guid>
            <pubDate>Sun, 07 Apr 2024 10:30:50 GMT</pubDate>
            <description><![CDATA[<p>회원가입, 로그인 기능 구현 시 Postman으로 jwt토큰을 헤더에 추가시키고 GET요청을 보낼 때, 403 Forbidden에러가 떴었다. 분명 AuthorizationFilter를 통과했을텐데, 왜 이런 에러가 뜬걸까? </p>
<p>아래는 필자의 AuthorizationFilter 코드이다.</p>
<pre><code class="language-@Override">    public GatewayFilter apply(Config config) {
        return (exchange, chain) -&gt; {
            ServerHttpRequest request = exchange.getRequest();

            if (!request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) {
                return onError(exchange, &quot;No authorization header&quot;, HttpStatus.UNAUTHORIZED);
            }



            String authorizationHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION).get(0);
            String jwt = authorizationHeader.replace(&quot;Bearer&quot;, &quot;&quot;);

            if (!isJwtValid(jwt)) {
                return onError(exchange, &quot;JWT token is not valid&quot;, HttpStatus.UNAUTHORIZED);
            }

            return chain.filter(exchange);
        };
    }</code></pre>
<p>valid된 jwt토큰이 아니면 JWT token is not valid 에러문이 떴어야 했는데, 그것도 아니었다. 즉, <strong>AuthoriztionFilter는 정상적으로 통과된것이었다.</strong></p>
<h3 id="경로-권한설정부분에서-문제가-있었다">경로 권한설정부분에서 문제가 있었다.</h3>
<p>혹시 경로에서 내가 권한을 잘 못 줬나는 생각에 WebSecurity설정 코드부분을 보았다. </p>
<pre><code>http.authorizeHttpRequests((authz) -&gt; authz
                                .requestMatchers(new AntPathRequestMatcher(&quot;/actuator/**&quot;)).permitAll()
                                .requestMatchers(new AntPathRequestMatcher(&quot;/h2-console/**&quot;)).permitAll()
                                .requestMatchers(new AntPathRequestMatcher(&quot;/users&quot;, &quot;POST&quot;)).permitAll()
                                .requestMatchers(new AntPathRequestMatcher(&quot;/h2-console/**&quot;)).permitAll()

//                        .requestMatchers(&quot;/**&quot;).access(this::hasIpAddress)
                                .requestMatchers(&quot;/**&quot;).access(
                                        new WebExpressionAuthorizationManager(&quot;hasIpAddress(&#39;127.0.0.1&#39;) or hasIpAddress(&#39;172.30.1.48&#39;)&quot;))
                                .anyRequest().authenticated()
                )
                .authenticationManager(authenticationManager)
                .sessionManagement((session) -&gt; session
                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS));

        http.addFilter(getAuthenticationFilter(authenticationManager));
        http.headers((headers) -&gt; headers.frameOptions((frameOptions) -&gt; frameOptions.sameOrigin()));</code></pre><p>보면은 일반적인 GET요청에도 authenticationFilter를 적용하고 있던것이었다!. 사실 Get요청시에는 인가필터만 적용하면 된다. 따라서 </p>
<blockquote>
<p>.requestMatchers(new AntPathRequestMatcher(&quot;/**&quot;, &quot;GET&quot;)).permitAll()</p>
</blockquote>
<p>를 추가하였더니 403에러가 사라지게 되었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[로그분석]이전 로그 파싱알고리즘의 문제점]]></title>
            <link>https://velog.io/@eun-woo/%EB%A1%9C%EA%B7%B8%EB%B6%84%EC%84%9D%EC%9D%B4%EC%A0%84-%EB%A1%9C%EA%B7%B8-%ED%8C%8C%EC%8B%B1%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EC%9D%98-%EB%AC%B8%EC%A0%9C%EC%A0%90</link>
            <guid>https://velog.io/@eun-woo/%EB%A1%9C%EA%B7%B8%EB%B6%84%EC%84%9D%EC%9D%B4%EC%A0%84-%EB%A1%9C%EA%B7%B8-%ED%8C%8C%EC%8B%B1%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EC%9D%98-%EB%AC%B8%EC%A0%9C%EC%A0%90</guid>
            <pubDate>Mon, 01 Apr 2024 09:17:58 GMT</pubDate>
            <description><![CDATA[<h3 id="hadoop로그">hadoop로그</h3>
<blockquote>
<p>41, Adding block pool BP-185116165-&lt;*&gt;-1512025890710,[&#39;155.230.91.226&#39;]</p>
</blockquote>
<blockquote>
<p>43 Cached dfsUsed found for /home/james/hadoop-2.7.4/hdfs/data/current/BP-185116165-&lt;<em>&gt;-1512025890710/current: &lt;</em>&gt;,&quot;[&#39;155.230.91.226&#39;, &#39;12435390464&#39;]</p>
</blockquote>
<blockquote>
<p>46 Adding replicas to map for block pool BP-185116165-&lt;*&gt;-1512025890710 on volume /home/james/hadoop-2.7.4/hdfs/data/current...,[&#39;155.230.91.226&#39;]</p>
</blockquote>
<blockquote>
<p>51 Periodic Directory Tree Verification scan starting at &lt;*&gt; with interval of 21600000ms,[&#39;1514035486079ms&#39;]</p>
</blockquote>
<blockquote>
<p>52 Block pool &lt;<em>&gt; (Datanode Uuid &lt;</em>&gt; service to deimos26/&lt;<em>&gt;:9000 &lt;</em>&gt; &lt;<em>&gt; &lt;</em>&gt; &lt;*&gt;,&quot;[&#39;BP-185116165-155.230.91.226-1512025890710&#39;, &#39;null)&#39;, &#39;155.230.91.226&#39;, &#39;beginning&#39;, &#39;handshake with NN&#39;]&quot;</p>
</blockquote>
<blockquote>
<p>15, Added global filter &#39;safety&#39; (class=org.apache.hadoop.http.HttpServer2$QuotingInputFilter),[]</p>
</blockquote>
<blockquote>
<p>16, Added filter &lt;<em>&gt; &lt;</em>&gt; to context &lt;*&gt;,&quot;[&#39;static_user_filter (class=org.apache.hadoop.http.lib.StaticUserWebFilter$StaticUserFilter)&#39;, &#39;datanode&#39;]&quot;</p>
</blockquote>
<blockquote>
<p>17, Added filter &lt;<em>&gt; &lt;</em>&gt; to context &lt;*&gt;,&quot;[&#39;static_user_filter (class=org.apache.hadoop.http.lib.StaticUserWebFilter$StaticUserFilter)&#39;, &#39;logs&#39;]&quot;</p>
</blockquote>
<blockquote>
<p>18, Added filter &lt;<em>&gt; &lt;</em>&gt; to context &lt;*&gt;,&quot;[&#39;static_user_filter (class=org.apache.hadoop.http.lib.StaticUserWebFilter$StaticUserFilter)&#39;, &#39;static&#39;]&quot;</p>
</blockquote>
<blockquote>
<p>154, Added filter &lt;<em>&gt; &lt;</em>&gt; to context &lt;*&gt;,&quot;[&#39;static_user_filter (class=org.apache.hadoop.http.lib.StaticUserWebFilter$StaticUserFilter)&#39;, &#39;secondary&#39;]&quot;</p>
</blockquote>
<blockquote>
<p>155, Added filter &lt;<em>&gt; &lt;</em>&gt; to context &lt;*&gt;,&quot;[&#39;static_user_filter (class=org.apache.hadoop.http.lib.StaticUserWebFilter$StaticUserFilter)&#39;, &#39;static&#39;]&quot;</p>
</blockquote>
<blockquote>
<p>156, Added filter &lt;<em>&gt; &lt;</em>&gt; to context &lt;*&gt;,&quot;[&#39;static_user_filter (class=org.apache.hadoop.http.lib.StaticUserWebFilter$StaticUserFilter)&#39;, &#39;logs&#39;]&quot;</p>
</blockquote>
<blockquote>
<p>3385 Added filter &#39;org.apache.hadoop.hdfs.web.AuthFilter&#39; (class=org.apache.hadoop.hdfs.web.AuthFilter),[]</p>
</blockquote>
<blockquote>
<p>3653, Added filter &lt;<em>&gt; &lt;</em>&gt; to context &lt;*&gt;,&quot;[&#39;RMAuthenticationFilter (class=org.apache.hadoop.yarn.server.security.http.RMAuthenticationFilter)&#39;, &#39;cluster&#39;]&quot;</p>
</blockquote>
<blockquote>
<p>193, Registering class &lt;<em>&gt; for class &lt;</em>&gt;,&quot;[&#39;org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ContainerEventType&#39;, &#39;org.apache.hadoop.yarn.server.nodemanager.containermanager.ContainerManagerImpl$ContainerEventDispatcher&#39;]&quot;</p>
</blockquote>
<p>문제점: </p>
<h4 id="1-명백히-port번호-ip_adress-node-name-등-이더라도-서로-다른-토큰이-안나오면-무조건-static으로-취급한다-ex-51-52번과-같이-포트번호가-9000이외가-없으니">1. 명백히 port번호, ip_adress, node name 등 이더라도 <strong>서로 다른 토큰이 안나오면</strong> 무조건 static으로 취급한다. ex: 51, 52번과 같이 포트번호가 9000이외가 없으니..</h4>
<h4 id="2-16-17-18번을-보면-filter-네임은-변수로-되어있지만-15번-3385번은-static-취급한다-왜냐하면-16-17-18은-15-3385와-토큰-수가-달라-아예-다른-이벤트로-취급되기-때문이다-다른-이벤트로-취급되기에--16-17-18은-filter-name토큰이-달라-로-취급하지만-15-3385내에서는-필터네임이-다-같기에-static으로-취급한다-로그-의미가-이토록-비슷한데-토큰수가-달라서-다른-이벤트로-취급되는-것이-문제">2. 16, 17, 18번을 보면 filter 네임은 변수로 되어있지만 15번, 3385번은 static 취급한다. 왜냐하면 16, 17, 18은 15, 3385와 토큰 수가 달라 아예 다른 이벤트로 취급되기 때문이다. 다른 이벤트로 취급되기에  16, 17, 18은 filter name토큰이 달라 <em>로 취급하지만, 15, 3385내에서는 필터네임이 다 같기에 static으로 취급한다. *</em>로그 의미가 이토록 비슷한데 토큰수가 달라서 다른 이벤트로 취급되는 것이 문제**</h4>
<h3 id="spark-로그">Spark 로그</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[아나콘다 가상환경 activate시 에러]]></title>
            <link>https://velog.io/@eun-woo/%EC%95%84%EB%82%98%EC%BD%98%EB%8B%A4-%EA%B0%80%EC%83%81%ED%99%98%EA%B2%BD-activate%EC%8B%9C-%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@eun-woo/%EC%95%84%EB%82%98%EC%BD%98%EB%8B%A4-%EA%B0%80%EC%83%81%ED%99%98%EA%B2%BD-activate%EC%8B%9C-%EC%97%90%EB%9F%AC</guid>
            <pubDate>Fri, 29 Mar 2024 06:32:31 GMT</pubDate>
            <description><![CDATA[<p>logparser를 돌리기 위해 가상환경을 세팅하고 </p>
<blockquote>
<p>conda activate logparser</p>
</blockquote>
<p>를 실행했을 시 </p>
<blockquote>
</blockquote>
<p>usage: conda [-h] [--no-plugins] [-V] COMMAND ...
conda: error: argument COMMAND: invalid choice: &#39;activate&#39; (choose from &#39;clean&#39;, &#39;compare&#39;, &#39;config&#39;, &#39;create&#39;, &#39;info&#39;, &#39;init&#39;, &#39;install&#39;, &#39;list&#39;, &#39;notices&#39;, &#39;package&#39;, &#39;remove&#39;, &#39;uninstall&#39;, &#39;rename&#39;, &#39;run&#39;, &#39;search&#39;, &#39;update&#39;, &#39;upgrade&#39;, &#39;build&#39;, &#39;content-trust&#39;, &#39;convert&#39;, &#39;debug&#39;, &#39;develop&#39;, &#39;doctor&#39;, &#39;index&#39;, &#39;inspect&#39;, &#39;metapackage&#39;, &#39;render&#39;, &#39;skeleton&#39;, &#39;repo&#39;, &#39;server&#39;, &#39;verify&#39;, &#39;token&#39;, &#39;env&#39;, &#39;pack&#39;)</p>
<p>라는 에러가 떴었다. 이것은 </p>
<blockquote>
<p>$ source ~/anaconda3/etc/profile.d/conda.sh</p>
</blockquote>
<p>이 명령어로 해결가능하다.
~에는 아나콘다3의 경로를 입력해주면 된다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[빌드, 빌드도구, (gradle, maven, jar, war)]]></title>
            <link>https://velog.io/@eun-woo/%EB%B9%8C%EB%93%9C-%EB%B9%8C%EB%93%9C%EB%8F%84%EA%B5%AC-gradle-maven-jar-war</link>
            <guid>https://velog.io/@eun-woo/%EB%B9%8C%EB%93%9C-%EB%B9%8C%EB%93%9C%EB%8F%84%EA%B5%AC-gradle-maven-jar-war</guid>
            <pubDate>Tue, 27 Feb 2024 04:30:46 GMT</pubDate>
            <description><![CDATA[<h2 id="maven-gradle">Maven, Gradle</h2>
<p>우리가 많이 쓰는 Maven과 Gradle은 빌드 관리 도구이다. 그렇다면 빌드는 뭐고, 빌드 관리 도구란 무엇일까?</p>
<h2 id="빌드">빌드</h2>
<p>빌드와 컴파일은 개념을 혼동하기가 쉬운데, 빌드는 컴파일뿐만이 아니라 소스코드 파일부터 시작해서 컴퓨터에서 실행할 수 있는 독립적인 형태로 변환되는 과정 전체를 말한다. 
<strong>자바를 예로 든다면</strong>, 개발자가 작성한 .java이 컴파일돼서 .class파일로 변환되고 resource를 .class에서 참조할 수 있는 위치로 옮긴다. 또한 META-INF와 MANIFEST.MF 들을 하나로 압축하는 과정이다. 즉, <strong>우리가 작성한 소스코드와 자원을 JVM이나 톰캣같은 WAS가 인식할 수 있도록 패키징하는 과정을 말한다.</strong></p>
<h2 id="빌드-관리-도구">빌드 관리 도구</h2>
<p>소스코드에서는 여러가지 외부 라이브러리를 참조해 사용하는데, 빌드 관리도구는 사용자가 관리할 필요없이 필요한 라이브러리를 자동으로 관리한다.</p>
<p>빌드관리 도구는 </p>
<blockquote>
<ol>
<li>종속성 다운로드</li>
<li>컴파일</li>
<li>컴파일된 바이너리 코드를 패키징(Packaging)</li>
<li>테스트 실행</li>
<li>프로덕션 시스템에 배포</li>
</ol>
</blockquote>
<p>Maven, Gradle이 이러한 빌드 관리도구이다. </p>
<h2 id="maven">Maven</h2>
<p>*<em>메이븐은 대표적인 Lifecycle관리 목적 빌드 도구이다. *</em></p>
<p>아래와 같은 라이프 사이클을 가진다.
(1) clean : 빌드 시 생성되어있었던 파일들을 삭제한다.
(2) validate : 프로젝트가 올바른지 확인하고 필요한 모든 정보를 사용할 수 있는지 확인하는 단계
(3) compile : 프로젝트 소스코드를 컴파일 하는 단계
(4) test : 단위 테스트를 수행하는 단계. 테스트 실패 시 빌드 실패로 처리하며, 스킵이 가능하다.
(5) package : 실제 컴파일된 소스 코드와 리소스들을 jar, war 등의 파일의 배포를 위한 패키지로 만든다.
(6) verify : 통합 테스트 결과에 대한 검사를 실행하여 품질 기준을 충족하는지 확인한다.
(7) site : 프로젝트 문서와 사이트 작성, 생성하는 단계
(8) deploy : 만들어진 package를 원격 저장소에 release하는 단계</p>
<p>또한 Maven은 필요한 라이브러리를 pom.xml에 정의한다. </p>
<h2 id="gradle">Gradle</h2>
<p>gradle은 Ant Builde와 groovy script를 기반으로 구축된, maven을 대항(?)하는 빌드 툴이다.
<strong>캐시를 사용하고, 빌드 속도가 Maven에 비해 10~100배 가량 빠르며,</strong> Java, C/C++, Python 등을 지원한다.</p>
<h3 id="groovy">Groovy</h3>
<blockquote>
<p>Groovy는 JVM에서 실행되는 스크립트 언어이다. 또한 컴파일 과정이 필요없다. Java문법과 유사하여 if else절등을 사용할 수 있다. </p>
</blockquote>
<h2 id="무엇을-사용하는-것이-좋을까">무엇을 사용하는 것이 좋을까?</h2>
<p>예전에야 Maven을 많이 썼지만, 지금은 속도와 가독성면에서 Gradle이 압도적이기에 Gradle로 많이 넘어온 추세라고 한다. 시간과 비용이 들지만 배워두는게 좋다고 생각하다. </p>
<h2 id="jar-war">JAR, WAR</h2>
<p>기본적으로 JAR, WAR 모두 Java의 jar 옵션 (java -jar)을 이용해 생성된 압축(아카이브) 파일로, 애플리케이션을 쉽게 배포하고 동작시킬 수 있도록 관련 파일(리소스, 속성 파일 등)을 패키징 한 것이다.</p>
<h3 id="jar-java-archive">JAR (Java Archive)</h3>
<blockquote>
<p>JAVA 어플리케이션이 동작할 수 있도록 자바 프로젝트를 압축한 파일
-Class (JAVA리소스, 속성 파일), 라이브러리 파일을 포함함
-JRE(JAVA Runtime Environment)만 있어도 실행 가능함 (java -jar 프로젝트네임.jar)</p>
</blockquote>
<h3 id="war-web-application-archive">WAR (Web Application Archive)</h3>
<blockquote>
<p>-Servlet / Jsp 컨테이너에 배치할 수 있는 웹 애플리케이션(Web Application) 압축파일 포맷
-웹 관련 자원을 포함함 (JSP, Servlet, JAR, Class, XML, HTML, Javascript)
-사전 정의된 구조를 사용함 (WEB-INF, META-INF)
<strong>-별도의 웹서버(WEB) or 웹 컨테이너(WAS) 필요</strong>
즉, JAR파일의 일종으로 웹 애플리케이션 전체를 패키징 하기 위한 JAR 파일이다.</p>
</blockquote>
<p>스프링부트는 내장WAS가 있어, WAR를 사용할 필욘 없다. 외장 WAS를 이용할 계획이 있다면 WAR를 사용하는 것이 좋겠지만,  그렇계획이 없다면 JAR를 사용하는 게 좋다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[1]카프카란?]]></title>
            <link>https://velog.io/@eun-woo/1%EC%B9%B4%ED%94%84%EC%B9%B4%EB%9E%80</link>
            <guid>https://velog.io/@eun-woo/1%EC%B9%B4%ED%94%84%EC%B9%B4%EB%9E%80</guid>
            <pubDate>Mon, 12 Feb 2024 15:41:29 GMT</pubDate>
            <description><![CDATA[<p>이 글은 [카프카, 데이터 플랫폼의 최강자 책]을 읽고 정리한 글입니다. </p>
<h2 id="카프카의-탄생배경">카프카의 탄생배경</h2>
<p><img src="https://velog.velcdn.com/images/eun-woo/post/08c2f766-255c-4161-9990-026dabe94bf9/image.png" alt="">
위 그림은 카프카를 개발해낸 링크드인이 카프카를 도입하기 전의 데이터 처리 시스템이다. </p>
<h4 id="위와-같은-아키텍처는-다음과-문제점이-있다">위와 같은 아키텍처는 다음과 문제점이 있다.</h4>
<ol>
<li><p>실시간 트랜잭션 처리와 비동기 처리가 동시에 이루어지지만 통합된 전송 영역이 없으니 복잡도가 증가할 수 밖에 없다. 따라서 문제를 발견하고 조치를 취하려면 여러 데이터 시스템을 확인해야한다.</p>
</li>
<li><p>데이터 파이프라인 관리의 어려움이 있다. 키-값 저장소, 모니터링 시스템, RDBMS, 하둡 등 제각기 파이프라인 별로 데이터 포맷과 처리하는 방법들이 달라 운영에 어려움이 있다. </p>
</li>
</ol>
<h4 id="따라서-카프카-창시자는-다음과-같은-목표를-가지고-새로운-시스템을-만들기-시작했다">따라서 카프카 창시자는 다음과 같은 목표를 가지고 새로운 시스템을 만들기 시작했다.</h4>
<ul>
<li>프로듀서와 컨슈머의 분리</li>
<li>메시징 시스템과 같이 영구 메시지를 여러 컨슈머에게 허용</li>
<li>높은 처리량을 위한 메시지 최적화</li>
<li>데이터가 증가함에 따라 스케일아웃이 가능한 시스템</li>
</ul>
<h4 id="따라서-다음과-같은-카프카-기반의-시스템을-만들었다">따라서 다음과 같은 카프카 기반의 시스템을 만들었다.</h4>
<p><img src="https://velog.velcdn.com/images/eun-woo/post/48756d13-aa29-47e1-81eb-c3439be76be8/image.png" alt=""></p>
<p>위와 같이 카프카를 적용한 후에는 모든 이벤트/데이터를 중앙에서 관리를 하게되었다. 또한 카프카가 제공하는 표준 포맷으로 연결되어있어 포맷 걱정도 할 필요가 없었다. 이젠 카프카에만 데이터를 전달하면 나머지는 필요한 곳 또는 다른 서비스들이 각자 가져갈 수 있어 자신의 업무에만 집중하면 되었다.</p>
<h2 id="카프카의-동작-방식과-원리">카프카의 동작 방식과 원리</h2>
<p><strong>기존 메시징 시스템을 사용하는 pub/sub 모델은 대규모 데이터보다는 간단한 이벤트를 서로 전송하는데 사용되었다.</strong> 왜냐하면 메시징 시스템의 교환기의 부하, 각 컨슈머의 큐 관리, 큐에 전달되고 가져가는 메시지의 정합성, 전달 결과를 관리하기 위한 내부 프로세스가 복잡하기 때문이었다. *<em>즉, 메시지의 보관, 교환, 전달 과정에서 신뢰성을 보장하는 것에 중점을 맞췄기 때문에 속도와 용량은 크게 고려하지 않았다. *</em></p>
<p>카프카는 메시지 시스템이 지닌 성능의 단점을 극복하기 위해, 메시징 시스템 내에서의 작업량을 줄이고 이렇게 절약한 작업량을 메시징 전달 성능에 집중시켜서 고성능 메시징 시스템을 만들었다. </p>
<h4 id="카프카의-메시지-전달-순서">카프카의 메시지 전달 순서</h4>
<ol>
<li>프로듀서는 새로운 메시지를 카프카로 보낸다.</li>
<li>프로듀서가 보낸 메시지는 카프카에 토픅에 도착해 저장된다.</li>
<li>컨슈머는 카프카 서버에 접속하여 새로운 메시지를 가져간다.</li>
</ol>
<h3 id="카프카의-특징">카프카의 특징</h3>
<p><strong>1. 프로듀서와 컨슈머의 분리:</strong>
카프카는 메시징 전송 방식 중 메시지를 보내는 역할과 받는 역할이 완벽하게 분리된 pub/sub방식을 적용했다.
<img src="https://velog.velcdn.com/images/eun-woo/post/2fa31013-d277-4473-bef6-2f886cfabc1c/image.png" alt="">
위 그림과 같이 서버가 1대가 더 추가된다면 단순하게 서버만 추가되는 것이 아니라 연동해야할 시스템이 많아지기 때문에 추가적인 작업도 매우 늘어난다. 게다가 일대일로 통신하고 있던 모니터링 서버에 문제가 생겨 응답이 늦어지는 경우가 발생하면, 연쇄작용으로 모니터링 서버와 연결된 다른 서비스 서버들에서도 지연 등의 이슈가 발생할 수 있다. 하지만 오른쪽과 같이 카프카를 중앙에 놓으면 서비스 서버들은 카프카로 메시지를 보내는 역할만 하면 되고, 모니터링이나 분석 시스템들도 카프카에 저장되어 있는 메시지만 가져오면 된다. </p>
<h4 id="2-멀티-프로듀서-멀티-컨슈머">2. 멀티 프로듀서, 멀티 컨슈머</h4>
<p><img src="https://velog.velcdn.com/images/eun-woo/post/322df647-a1d7-46d9-95f2-bd681f37bc1b/image.png" alt="">
카프카는 하나의 토픽에 여러 프로듀서 또는 컨슈머들이 접근 가능한 구조로 되어있다. 이렇게 하면 하나의 데이터를 다양한 용도로 사용하는 요구를 쉽게 충족할 수 있다.</p>
<h4 id="3-디스크에-메시지-저장">3. 디스크에 메시지 저장</h4>
<p>트래픽이 일시적으로 폭주해 컨슈머의 처리가 늦어지더라도 카프카의 디스크에 안전하게 보관되어있기 때문에, 컨슈머는 메시지 손실 없이 메시지를 가져갈 수 있다. </p>
<h4 id="4-확장성">4. 확장성</h4>
<p>카프카 클러스터는 3대의 브로커로 시작해 수십 대의 브로커로 확장 가능하다.</p>
<h4 id="5-높은-성능">5. 높은 성능</h4>
<p>카프카는 고성능을 위해 내부적으로 분산 처리, 배치 처리 등 다양한 기법을 사용하고 있다.</p>
<p>이상으로 카프카의 전체적인 탄생배경, 구조, 특징 등을 알아보았습니다. 다음 편에서는 카프카의 디자인에 대해 알아보겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[스프링부트]IOC, DI를 알아보자]]></title>
            <link>https://velog.io/@eun-woo/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8IOC-DI%EB%A5%BC-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@eun-woo/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8IOC-DI%EB%A5%BC-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Sun, 04 Feb 2024 04:21:36 GMT</pubDate>
            <description><![CDATA[<h2 id="problem">Problem</h2>
<p>사용자가 매 번 객체를 생성하고, 관리할 때마다 객체 간의 결합성이 커진다. 그럴 때마다 코드의 복잡성은 커지며 사용자는 번거로움을 느낀다. <strong>이것은 곧 요구사항 변경의 취약을 의미한다</strong>. 객체인스턴스의 생성, 소멸을 관리해주는 게 따로 있을 수 없을까?</p>
<h2 id="ioc-컨테이너">IOC 컨테이너</h2>
<blockquote>
<p>컨테이너는 객체의 생성주기를 관리하고, 생성된 객체에게 추가적인 기능을 제공하는 것을 뜻한다.</p>
</blockquote>
<p>스프링 프레임워크도 이러한 객체의 생성, 소멸, 의존성 등을 담당하는 컨테이너가 따로 있는 데 이것이 바로 IOC 컨테이너이다. </p>
<p>*<em>인스턴트의 생성부터 소멸까지 생명주기를 사용자가 아닌 컨테이너가 따로 관리해주어 사용자는 오로지 로직에만 집중하면 된다. *</em></p>
<h1 id="how">How?</h1>
<p><img src="https://velog.velcdn.com/images/eun-woo/post/7d63cc0f-6d1b-43d2-9578-a38b96a498cc/image.png" alt=""></p>
<p>위 그림을 보자. 사용자는 Factory라는 클래스의 객체를 Container에 등록하고 싶다. 그러면 @Component나 @Bean을 통해 스프링 빈으로 등록하면 된다. 그러면 Factory 객체는 따로 사용자가 아닌 컨테이너가 따로 관리해준다. 사용자는 번거롭게 Factory객체를 생성을 하지않고 그저 @Autowired를 붙여 컨테이너에서 불러내주기(<strong>DI</strong>)만 하면 된다. </p>
<h2 id="iocinversion-of-control">IOC(Inversion of Control)</h2>
<p>이렇게 사용자가 객체를 관리하는 것이 아닌 컨테이너가 따로 관리해 사용자가 로직에만 집중할 수 있게 하는 것은 제어의 역전 즉, IOC라고 한다.</p>
<h2 id="didependency-injection">DI(Dependency Injection)</h2>
<p>사용자는 그저 객체를 생성하지 않고, @Autowired를 통해 객체를 삽입해 불러올 수 있는데, 이것을 의존성 주입 즉, DI라고 한다.</p>
]]></description>
        </item>
    </channel>
</rss>