<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>character_c.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sun, 28 Jan 2024 12:55:40 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. character_c.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/character_c" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[DB] ACID란?]]></title>
            <link>https://velog.io/@character_c/DB-ACID%EB%9E%80</link>
            <guid>https://velog.io/@character_c/DB-ACID%EB%9E%80</guid>
            <pubDate>Sun, 28 Jan 2024 12:55:40 GMT</pubDate>
            <description><![CDATA[<h1 id="acid란">ACID란?</h1>
<p>Database의 트랜잭션이 안전하게 수행된다느것을 보장하기 위한 성질을 가리키는 약어이다</p>
<blockquote>
<p>Transaction 이란 데이터베이스 상태를 변화시키는 쪼갤 수 없는 작업의 최소 단위
<a href="https://velog.io/@character_c/DB-Transaction%EC%9D%B4%EB%9E%80">https://velog.io/@character_c/DB-Transaction이란</a></p>
</blockquote>
<h2 id="atomicity-원자성">Atomicity (원자성)</h2>
<p>트랜잭션은 원자와 같이 나뉘어질 수 없기 때문에 트랜잭션의 결과는 성공 혹은 실패만 존재한다</p>
<p>일부는 성공 일부는 실패한다면 트랜잭션의 결과를 예상할 수 없고 불안정한 상태가 된다</p>
<blockquote>
<p>안전성을 보장하기 위해 하나의 트랜잭션의 모든 작업은 <strong>모두 성공하거나 모두 실패</strong>해야하며 이를 위해 일부가 실패할 경우 성공한 작업들도 Rollback을 수행하여 전체 작업을 실패로 만든다</p>
</blockquote>
<p>Ex) A계좌에서 10만원의 돈을 인출하여 B계좌로 입금하는 트랜잭션을 예로 들어보면 트랜잭션에는 다음과 같은 작업들이 있다</p>
<ol>
<li>A계좌를 조회한다</li>
<li>A계좌에서 10만원 을 인출한다</li>
<li>B계좌에 10만원을 입금한다</li>
</ol>
<p>이때 2번의 인출까지는 성공하였지만 3번 단계에서 실패가 발생한 상태로 종료된다면 A계좌에서 사라진 10만원은 더 이상 존재하지 않는다
그렇기 때문에 3번단계에서 실패가 발생한다면 2번의 인출 또한 원복하여 Data는 안전하게 보존하고 트랜잭션은 실패로 끝나야 한다</p>
<p><img src="https://velog.velcdn.com/images/character_c/post/83c4bb2a-2f75-45ce-b803-9f7e06e69ed8/image.png" alt=""></p>
<h2 id="consistency일관성">Consistency(일관성)</h2>
<blockquote>
<p>트랜잭션 이전과 이후의 Database의 <strong>상태는 일관되게 유지</strong>되어야 한다
Database의 <strong>상태라함은 Database에 설정된 제약과 규칙을 포함</strong>한다</p>
</blockquote>
<p>Ex) 은행에서 신규 계좌를 발급할때 계좌DB에는 모든 계좌는 계좌번호가 있어야 한다는 규칙이 있다고 가정한다
트랜잭션 이후 번호가 없는 계좌가 추가된다거나, 계좌번호만 삭제된다면 모든 계좌는 계좌번호가 있어야 한다는 규칙이 모든 계좌에 계좌번호가 있어야 하는것은 아니다 로 성질이 변하기 때문에 이는 일관되지 않다</p>
<h2 id="isolation격리고립성">Isolation(격리,고립성)</h2>
<blockquote>
<p>모든 트랜잭션은 다른 트랜잭션과 독립되어야 한다
이를 다르게 표현하면 트랜잭션이 <strong>동시에 수행된 결과와 각각 순차적으로 수행된 결과가 같아야한다</strong></p>
</blockquote>
<p>Ex) 만원이 들어있는 통장에서 6천원(A),4천원(B)을 출금하는 2개의 트랜잭션이 발생했다
각각의 트랜잭션은 다음의 작업을 포함한다</p>
<blockquote>
</blockquote>
<ol>
<li>계좌의 잔금을 조회한다</li>
<li>A : 6천원을 출금한다, B : 4천원을 출금한다</li>
</ol>
<p>트랜잭션이 각각 수행된다면 다음과 같다</p>
<blockquote>
<p>A-계좌의 잔금을 조회한다(잔금  : 10,000)
A-6천원을 출금한다(10,000-6,000)
B-계좌의 잔금을 조회한다(잔금 : 4,000)
B-4천원을 출금한다(4,000-4,000)
<strong>결과 잔금 : 0</strong></p>
</blockquote>
<p>트랜잭션이 동시에 수행되면 다음과 같다</p>
<blockquote>
<p>A-계좌의 잔금을 조회한다(잔금  : 10,000)
B-계좌의 잔금을 조회한다(잔금 : 10,000)
A-6천원을 출금한다(10,000-6,000)
B-4천원을 출금한다(10,000-4,000)
<strong>결과 잔금 : 6,000</strong></p>
</blockquote>
<p>A 트랜잭션에서 발생한 Update가 B트랜잭션으로 인해 사라지면서 결과가 달라졌다(Lost Update)</p>
<p>이러한 현상을 방지하기 위해 각각의 트랜잭션은 독립적으로 수행되어야 한다.
Lost Update외 Dirty reads, Non-repeatable reads, Phantom Reads 등의 현상이 있다
Isolation Level(격리 수준)에 따라 더 많은 현상을 방지 할 수 있으나 동시처리 성능이 떨어지는 단점이 있다.</p>
<p>이 부분에 대해서는 추가적으로 정리가 필요할것 같다</p>
<h2 id="durability지속성">Durability(지속성)</h2>
<blockquote>
<p><strong>성공적으로 종료된 트랜잭션은 영구적으로 기록이 남아야한다</strong></p>
</blockquote>
<p>트랜잭션이 성공적으로 종료되었으나 결과가 Disk에 저장되기전에 시스템 문제등으로 Down이 발생하여 트랜잭션의 결과가 사라지면 안된다는 얘기다</p>
<p>Ex) A계좌에 10만원을 입금하는 트랜잭션이 있다
사용자는 A계좌에 10만원을 입금했고 성공적으로 종료됐다는 Ack를 받았다
Ack가 전달된 뒤 DBMS가 종료되어 <strong>10만원을 입금했다는 기록이 사라진다면 성공했음에도 돈이 사라지는 문제가 발생</strong>된다</p>
<h2 id="결론">결론</h2>
<p>ACID는 트랜잭션이 안정적으로 수행된다는 성질을 나타내는 지표이고 DBMS마다 성질을 만족하는 방법은 다를 수 있다.
개발을 진행할 때 RDBMS가 어떻게 이 성질을 만족시키는지를 이해하지 않더라도 RDBMS가 지원하는 기능이나 특징만 알더라도 충분히 활용할 수 있다</p>
<p>다만 안전성을 중시하는 ACID 모델의 DBMS와 달리 가용성을 중시하는 DBMS도 있다. 아직 존재하지 않지만 새로운 DBMS를 이해 할때도 이러한 성질에 대해서 알고 있는것은 도움이 될 수 있다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Redis] Redis 구성 : Cluster vs Sentinel]]></title>
            <link>https://velog.io/@character_c/Redis-Redis-%EA%B5%AC%EC%84%B1-Cluster-vs-Sentinel</link>
            <guid>https://velog.io/@character_c/Redis-Redis-%EA%B5%AC%EC%84%B1-Cluster-vs-Sentinel</guid>
            <pubDate>Sun, 28 Jan 2024 11:44:06 GMT</pubDate>
            <description><![CDATA[<h1 id="redis-architecture">Redis Architecture</h1>
<h2 id="stand-alonereplication">Stand-Alone(Replication)</h2>
<p><img src="https://velog.velcdn.com/images/character_c/post/a53631fe-4dfb-485e-873b-8ee73386f073/image.png" alt=""></p>
<p>Stand-alone은 Redis를 단일서버로 구성하여 운영하는 방식으로 장애발생시 Data의 유실, 가용성 확보에 취약하다
Data유실을 최소화 하기 위해  Data백업을 위한 Replication을제공하고 있다.</p>
<p><img src="https://velog.velcdn.com/images/character_c/post/6783fd67-4bdc-49b9-a4fb-db8451fc8317/image.png" alt=""></p>
<p>Master서버에 장애 발생시 Replication서버를 Master서버로 활용이 가능하다
단, 이때 Replication서버는 운용자가 직접 기동시켜야하며 별도의 장비가 없다면 Client에서 타깃(Redis Master)서버 주소를 변경해주어야 한다</p>
<h2 id="sentinel">Sentinel</h2>
<p><img src="https://velog.velcdn.com/images/character_c/post/2a6a8908-6b81-471d-92a0-94e1e86f85ae/image.png" alt=""></p>
<p>Redis에서는 고가용성 확보를 위하여 Sentinel 기능을 지원한다
Sentinel은 Redis Master서버를 <span style="color:red"><strong>모니터링</strong></span> 하다가 Master서버에 문제가 발생하면 Slave서버로 Failover를 수행하는 역할을 한다
Slave서버는 Master의 Replica서버로 FailOver가 되면 Slave서버가 새로운 Master서버가된다</p>
<p><img src="https://velog.velcdn.com/images/character_c/post/8450a6cb-b728-4c28-989c-714d6fa06aa2/image.png" alt=""></p>
<p>장애여부 판단을 위하여 Sentinel은 3대 이상의 홀수로 구성한다
1대로 구성시 Master서버가 아닌 <span style="color:red"><strong>Sentinel서버의  장애(네트워크차단)</strong></span>로 인한 장애 상황을 탐지할 수 없다
2대로 구성시 1대에만 장애가 발생하면 <span style="color:red"><strong>1:1상황으로 동일하게 판단이 불가능</strong></span>하다
3대로 구성시 2대에서 장애가 발생하면 <span style="color:red"><strong>과반수 이상이 장애로 판단하면 Sentinel서버가아닌 Master 서버의 문제로 판단</strong></span>하여 FailOver를 수행한다</p>
<p>홀수로 구성된 Sentinel 서버는 Quorum을 구성하며 설정한 임계치 이상으로 Sentinel서버가 장애를 인지하면 FailOver를 수행한다</p>
<p>장애탐지는 아래와 같이 판단된다</p>
<blockquote>
</blockquote>
<p>Subjectively Down(SDOWN)</p>
<ul>
<li>Sentinel -&gt; Master로 HealthCheck(Ping)을 수행하며 응답이 없는 경우 탐지된다<blockquote>
</blockquote>
Objectively Down(ODOWN)</li>
<li>설정된 Quorum 이상 SDOWN이 탐지되면 ODWON으로 인지하고 FailOver를 수행한다</li>
</ul>
<p><img src="https://velog.velcdn.com/images/character_c/post/7005ee5f-6f3e-41e5-881b-4d226fa3c20c/image.png" alt=""></p>
<p>또한 Sentinel 구성에서 Client - Sentienl - Master로 구성이 되어 Master서버가 변경되더라도 <span style="color:red"><strong>Sentinel에서 Redirection을 수행</strong></span>하기 때문에 Client에서 이를 관리할 필요가 없다</p>
<h2 id="cluster">Cluster</h2>
<p><img src="https://velog.velcdn.com/images/character_c/post/5b1c88b1-b1b2-4901-b67d-c60bfcc796d5/image.png" alt=""></p>
<p>Cluster는 여러대의 Master가 존재할 수 있다. 여러대의 Master에 Hash Slot을 통해 Data를 분산해서 저장한다 ( <strong>Sharding을 지원한다</strong> )
Data를 Single-Master가 처리한다면 Scale-Up을 해야하지만 <strong>Multi-Master에서 분산 처리하기 때문에 Scale-Out으로 더 많은 처리</strong>가 가능하다
Redis Cluster는 Scale-Out시 Online으로 ReSharding 기능을 지원한다</p>
<p>반면 단점으로는 Multi Key Operation이 제한되며 Database도 0번만 사용이 가능하다</p>
<p><img src="https://velog.velcdn.com/images/character_c/post/73100eb0-65aa-486f-9aea-787b42f3f9c3/image.png" alt="">
Cluster의 Node는 모두 연결 되어 있다 ( <strong>Full-Mesh</strong> ) 모두 연결된 Node들은 Gossip Protocol을 통해 상태를 공유한다. Gossip에서 의미하는것처럼 소문이 퍼저나가듯 Node사이의 정보들이 퍼지게 된다.</p>
<p><img src="blob:https://velog.io/352a4fcb-6222-412e-b66a-46c53735ab0c" alt="업로드중.."></p>
<p>Cluster는 Master Node중 일부의 장애가 탐지되면 Replica Server를 Master로 승격시킨다
Cluster는 Gossip Protocol을 통해 통신한다 최초로 장애를 탐지한 서버가 장애가 의심되는 메시지(PFAIL)를 보낸다 다른 서버들 또한 메시지를 보내고 과반수를 넘어서면 의심이 아닌 장애 확정 메시지(FAIL)를 송출한다
이 후 Replica서버를 Master서버로 승격 시킨다</p>
<p>Redis의 복제는 비동기 복제로 복제가 완료되지않은 상태에서도 ack를 전달하여 consistency가 약하다. 일부 데이터의 유실이 발생할 수 있다</p>
<h2 id="결론">결론</h2>
<p>Sentinel과 Cluster를 비교하면 Sentinel은 단일 서버의 고가용성에 초점을 두고 Cluster는 확장성과 분산처리에 초점을 둔다
Redis구축시 요구되는 Spec에 따라 고려되어야 한다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DB] Transaction이란]]></title>
            <link>https://velog.io/@character_c/DB-Transaction%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@character_c/DB-Transaction%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Sun, 21 Jan 2024 04:20:43 GMT</pubDate>
            <description><![CDATA[<h1 id="트랜잭션transaction이란">트랜잭션(Transaction)이란?</h1>
<blockquote>
<p>데이터베이스 상태를 변화시키는 쪼갤 수 없는 작업의 최소 단위</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/character_c/post/facede1a-4729-4829-9c22-8ff9ad2cd5cc/image.png" alt=""></p>
<p>하나의 트랜잭션은 한개의 업무가 있을 수도 있고 N개의 업무가 있을 수도 있다</p>
<p><img src="https://velog.velcdn.com/images/character_c/post/51f3a3e7-b84d-4735-a3e6-1c1334bc099f/image.png" alt="">
Transaction이 더 이상 쪼개지지 않는 다는것은 다음과 같다</p>
<p><SPAN style='color:green'>Transaction1</Span>에 포함된 모든 업무가 성공했고, <SPAN style='color:green'>Transaction1</span>은 성공이라 표현할 수 있다</p>
<p><SPAN style='color:red'>Transaction2</span>에 포함된 모든 업무가 실패했고, <SPAN style='color:red'>Transaction2</span>는 실패라 표현할 수 있다</p>
<p><SPAN style='color:rgb(128,128,128)'>Transaction3</span>에 포함된 업무중 <strong>일부는 성공했고, 일부는 실패했다.</strong> Transaction의 일부는 성공했고 일부는 실패했다라 표현할 수 있지만 <strong>이는 Transaction이 쪼개어 질 수 있어야 가능하다.</strong></p>
<p>그렇기 때문에 <SPAN style='color:rgb(128,128,128)'>Transaction3</span>은 존재 할 수 없고, Database는 Transaction3과 같은 상태가 발생하면 업무1~3을 Rollback하여 <SPAN style='color:red'>Transaction2</span>와 같게 만든다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Redis] Redis 기본 개념 잡기]]></title>
            <link>https://velog.io/@character_c/Redis-Redis-%EA%B8%B0%EB%B3%B8-%EA%B0%9C%EB%85%90-%EC%9E%A1%EA%B8%B0</link>
            <guid>https://velog.io/@character_c/Redis-Redis-%EA%B8%B0%EB%B3%B8-%EA%B0%9C%EB%85%90-%EC%9E%A1%EA%B8%B0</guid>
            <pubDate>Tue, 16 Jan 2024 14:05:41 GMT</pubDate>
            <description><![CDATA[<h1 id="redis란">Redis란?</h1>
<p>Redis에 대하여 위키백과에서는 다음과 같이 설명하고 있다</p>
<blockquote>
<p>&quot;키-값&quot; 구조의 비정형 데이터를 저장하고 관리하기 위한 오픈 소스 기반의 비관계형 <strong>데이터베이스 관리 시스템(DBMS)</strong> </p>
</blockquote>
<p>Redis도 흔히 알고 있는 Mysql, Oracle DB와 같이 데이터를 저장하기 위한 저장소라는 얘기이다.</p>
<p>조금 더 정확히는 비관계형(NoSQL) DBMS이기 때문에 MongoDB, HBase에 더 가깝다</p>
<h1 id="그럼-왜-redis를-사용하는가">그럼 왜 Redis를 사용하는가?</h1>
<h2 id="redis의-특징1-속도">Redis의 특징1 속도</h2>
<p>Redis를 사용할때 가장 먼저 떠올리는 것은 Data에 접근하는 속도이다.
Redis는 Data를 Disk가 아닌 Memory에 저장한다
<img src="https://velog.velcdn.com/images/character_c/post/c9394574-8a52-4638-93cc-e79246e37621/image.png" alt=""></p>
<blockquote>
<p>기존의 DBMS들은 데이터를 보관하기 위하여 Disk영역에 Data를 기록하였지만
<strong>Redis는 Memory영역에  Data를 기록하여 빠른 접근속도를 지원합니다</strong></p>
</blockquote>
<p>다만 동일한 용량이라하더라도 Memory는 Disk보다 더 비싸기 때문에 용량에 대한 제한이 있고 Memory의 휘발성으로 Data가 삭제될 가능성이 더 높기 때문에</p>
<blockquote>
<p>Redis는 일반적으로 대용량 데이터를 지속적으로 보관하기 위한 Main DBMS에 적합하지는 않습니다</p>
</blockquote>
<p>Redis에서는 Memory가 한계치에 도달했을때를 위한 몇가지 정책을 Configuration으로 제공하고 있습니다</p>
<p>명시적으로 Data 삭제를 요청할때까지 새로운 값을 추가하지 못한다거나, 사용한지 오래된 Data, 사용빈도가 적은 Data를 우선 삭제하는 등. Option에 대해서는 설치시에 Configuration 관련해서 정리가 필요할듯 하다</p>
<h2 id="redis의-특징2-다양한-자료구조-지원">Redis의 특징2 다양한 자료구조 지원</h2>
<blockquote>
<p><strong>Re</strong>mote <strong>Di</strong>ctionary <strong>S</strong>erver의 앞글자를 따서 Redis라고 한다</p>
</blockquote>
<p>Redis는 그 이름처럼 Key-Value형태를 지원하는 DBMS입니다. Redis에서는 일반 String뿐 아니라 Lists, Sets, Sorted sets, Hash 등을 지원하여 프로그램 개발에 있어서도 용이합니다</p>
<blockquote>
<p><strong>List, Set, Sorted set, Hash 등을 지원한다</strong></p>
</blockquote>
<h2 id="redis의-특징3-영속성persistence를-지원">Redis의 특징3 영속성(Persistence)를 지원</h2>
<p>Redis는 IMDB의 일종으로 메모리의 휘발성 때문에 데이터 보관에 취약하다고 했지만 Redis는 이를 보완하기 위해 Memory와 Disk영역을 모두 활용한다</p>
<blockquote>
<p>RDB(Redis Database)   방식 : 주기적으로 <strong>Snapshot을 Disk에 남김</strong>
AOF(Append Only File) 방식 : <strong>쓰기 Log를 파일(Disk)에 저장하는 방식</strong></p>
</blockquote>
<h3 id="aof-방식">AOF 방식</h3>
<p>AOF방식은 Data의 변경이 일어나는 쓰기동작에 대한 Log를 파일에 남겨두고 Redis Server가 기동시에 <strong>Log에 있는 동작을 재수행하는것으로 영속성을 보장한다</strong></p>
<p>Log를 즉시 Disk에 기록하기 때문에 <strong>실시간으로 데이터의 &quot;백업&quot;이 이루어지고, 실수로 DB를 잘못 다루더라도 Log를 수정하면 데이터의 복원도 가능하다는 장점이 있다</strong></p>
<p>반면 AOF는 쓰기동작(Insert/Update/Delete)에 관한 모든 로그를 기록하기 때문에 쓰기동작이 빈번하게 발생하는 경우 로그 사이즈가 굉장히 증가하게 되고 복원시 시간이 오래걸린다는 단점이 있다.</p>
<h3 id="rdb-방식">RDB 방식</h3>
<p>RDB 방식은 <strong>Redis의 Data를 압축하여 그대로 저장하기 때문에 저장하는 크기도 상대적으로 작고 &quot;복원&quot;속도도 빠르다</strong></p>
<p>반면 실시간으로 데이터의 백업이 이루어지지 않기 때문에 스냅샷을 남기기전에 문제가 발생하는 경우 데이터의 유실이 발생 할 수 있다
또한 데이터 전체를 백업하기 때문에 백업속도는 상대적으로 느리다</p>
<h3 id="rdbaof">RDB+AOF</h3>
<p>RDB 방식으로 스냅샷을 남기고 다음 설정시간까지의 데이터는 AOF로 백업을 진행하는 방식이다. 두가지 방식의 장점을 얻고 단점을 상호 보완할 수 있어 많이 사용하는 방식이다.</p>
<h2 id="redis의-특징4-single-thread">Redis의 특징4 Single Thread</h2>
<p>Redis는 Single Thread로 동작합니다
그렇기 때문에 한번에 하나의 요청만을 처리하고 이를 통해 원자성(Atomic)을 보장한다고 하는데 이렇게만 보면 잘 이해가 되지는 않는다</p>
<p>한번에 하나의 요청만을 처리하기 때문에 Race Condition에 의한 데이터 불일치가 발생하지 않을 수 있고
또한 하나의 요청을 순차처리하기 때문에 장시간이 걸리는 요청이 있다면 뒤의 요청들이 밀려 지연이 발생 할 수 있다는 설명들을 가볍게 보면 이해가 된다</p>
<p>하지만 Redis에서 AOF방식의 Log를 수정하는것 외에 자체적으로 Rollback을 지원하지 않고 있고
여러 서버에서 동시에 접근시에 다른 DBMS들과 동일하게 보장이 되는지에 대해서는 의문이 남은 상태이니</p>
<p>우선은 Single Thread로 동작한다는것만 인지하고 원자성과 트랜잭션에 대한 부분은 조금 더 찾아봐야겠다</p>
<h1 id="redis의-사용처">Redis의 사용처</h1>
<p>Redis는 위와 같은 특징들이 있기 때문에 캐싱서버, 세션관리와 같은 기능을 지원하기 위해 많이 사용된다. 메인 DBMS로 데이터를 보관하는것에는 문제가 있지만 IoT단말과 같이 통신이 주를 이루거나 인증에 관한 경우 Main DBMS의 부하를 줄이고 시스템 성능을 높일수 있다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] Collection Framework]]></title>
            <link>https://velog.io/@character_c/JAVA-Collection-Framework</link>
            <guid>https://velog.io/@character_c/JAVA-Collection-Framework</guid>
            <pubDate>Mon, 08 Aug 2022 16:24:48 GMT</pubDate>
            <description><![CDATA[<h2 id="collection-framework란">Collection Framework란?</h2>
<p>Collection을 구성하고, 구성된 Data를 Handling 하기위한 Interface와 Class들의 집합체 라고 한다.</p>
<p>프로그래밍을 하다보면 임시적으로 데이터를 저장하고 다루는 일이 빈번한데,
이때 <span style='color:red'>데이터를 저장하는 자료구조와 데이터를 처리하는 API들을 잘만들어서 정리해둔것</span>이 Collection Framework</p>
<p>예를들면 
List는 데이터를 저장시 순서를 기록하고 중복된 데이터를 허용하는 방식이고
Set은 데이터를 저장시 순서를 보장하지 않고 중복된 데이터를 허용하지 않는다.</p>
<p>프로그래밍을 할때는 각각의 특징에 맞게 사용하면 된다.</p>
<h2 id="collection-framework-구조구성">Collection Framework 구조(구성)</h2>
<p><img src="https://velog.velcdn.com/images/character_c/post/f755c4d3-33fc-4d0f-9bab-696948d81373/image.jpeg" alt=""></p>
<p><br><br></p>
<p>Collection Framework은 크게 <strong>Collection</strong>과 <strong>Map</strong> 두가지의 Interface로부터 시작된다</p>
<p><strong>Iterable</strong>을 상속받는 <strong>Collection</strong>은 값(Element)의 집합체이고
<strong>Map</strong>은 값(Value)을 찾기 위해 Key를 지정한 Key-Value 쌍의 집합체이다
<br><br></p>
<table>
<thead>
<tr>
<th>Interface명</th>
<th>특징</th>
<th>대표예시</th>
</tr>
</thead>
<tbody><tr>
<td>Collection</td>
<td>Object의 단독 구성</td>
<td>ArrayList, HashSet...</td>
</tr>
<tr>
<td>Map</td>
<td>Key-Value의 Pair 구성</td>
<td>HashMap...</td>
</tr>
</tbody></table>
<hr>
<p><br></br>
Collection을 상속받은 주요 Interface는 <strong>List / Set / Queue</strong>가 있다.</p>
<table>
<thead>
<tr>
<th>Interface명</th>
<th>특징</th>
<th>대표예시</th>
</tr>
</thead>
<tbody><tr>
<td>Set</td>
<td>순서가 없는 값의 집합, 중복을 허용하지 않음</td>
<td>HashSet</td>
</tr>
<tr>
<td>List</td>
<td>순서가 있는 값의 집합, 중복을 허용</td>
<td>LinkedList</td>
</tr>
<tr>
<td>Queue</td>
<td>순서가 있는 값의 집합, 중복을 허용 / 선입선출(FIFO)</td>
<td>PriorityQueue</td>
</tr>
</tbody></table>
<p><br><br></p>
<p>결국 Collection Framework은 아래 4가지의 Interface를 상속받아 데이터 구조를 확장한다</p>
<table>
<thead>
<tr>
<th>Interface명</th>
<th>순서</th>
<th>중복</th>
<th>특징</th>
<th>대표예시</th>
</tr>
</thead>
<tbody><tr>
<td>Set</td>
<td>X</td>
<td>X</td>
<td>값의 집합</td>
<td>HashSet</td>
</tr>
<tr>
<td>List</td>
<td>O</td>
<td>O</td>
<td>값의 집합</td>
<td>ArrayList</td>
</tr>
<tr>
<td>Queue</td>
<td>O</td>
<td>O</td>
<td>선입선출(FIFO)</td>
<td>PriorityQueue</td>
</tr>
<tr>
<td>Map</td>
<td></td>
<td>KEY(X), Value(O)</td>
<td>Key-Value의 Pair 구성</td>
<td>HashMap</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 신고 결과 받기]]></title>
            <link>https://velog.io/@character_c/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%8B%A0%EA%B3%A0-%EA%B2%B0%EA%B3%BC-%EB%B0%9B%EA%B8%B0</link>
            <guid>https://velog.io/@character_c/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%8B%A0%EA%B3%A0-%EA%B2%B0%EA%B3%BC-%EB%B0%9B%EA%B8%B0</guid>
            <pubDate>Sun, 07 Aug 2022 13:53:57 GMT</pubDate>
            <description><![CDATA[<h3 id="생각해보기">생각해보기</h3>
<p>결과적으로 원하는것은 <strong><em>각 유저별로 처리결과를 받은 횟수를 담은 배열</em></strong> 이다.</p>
<blockquote>
</blockquote>
<p>각 유저는 <span style='color:red'><strong>한 번에 한 명의 유저를 신고</strong></span>할 수 있습니다.
<strong>신고 횟수에 제한은 없습니다.</strong> 서로 다른 유저를 계속해서 신고할 수 있습니다.
한 유저를 여러 번 신고할 수도 있지만, <span style='color:red'><strong>동일한 유저에 대한 신고 횟수는 1회로 처리</strong></span>됩니다.
k번 이상 신고된 유저는 게시판 이용이 정지되며, 해당 유저를 신고한 모든 유저에게 정지 사실을 메일로 발송합니다.
유저가 신고한 모든 내용을 취합하여 마지막에 한꺼번에 게시판 이용 정지를 시키면서 정지 메일을 발송합니다.</p>
<p><span style='color:red'><strong>동일한 유저에 대한 신고 횟수는 1회로 처리</strong></span>된다는 것을 보면, 중복신고에 대해서도 제거해줄 필요가 있고</p>
<p>중복이 제거되면
Count가 K이상인 Block된 ID 배열을 만들고
유저ID별로 신고한 ID 배열을 갖는 Map을 만들고
두 개의 교집합 사이즈들을 배열로 만들면........오래걸리나?</p>
<hr>
<h3 id="풀어보기">풀어보기</h3>
<pre><code class="language-java">import java.util.HashSet;
import java.util.Arrays;
import java.util.Map;
import java.util.HashMap;

class Solution {
    public int[] solution(String[] id_list, String[] report, int k) {
        int[] answer = {};
        answer = new int[id_list.length]; // answer Size 설정

        HashSet&lt;String&gt; reportHashSet = new HashSet&lt;&gt;(Arrays.asList(report)); // Report HashSet 변환하여 중복제거
        HashMap&lt;String, HashSet&lt;String&gt;&gt; reportedIdsById = new HashMap&lt;&gt;(); // 신고자별 신고한ID 배열
        HashMap&lt;String, HashSet&lt;String&gt;&gt; reportingIdsById = new HashMap&lt;&gt;(); // 신고당한ID별 신고자 배열
        HashSet&lt;String&gt; blockedIds = new HashSet&lt;&gt;(); // 이용정지 ID 배열

        for(String id : id_list){ // 배열초기화
            HashSet&lt;String&gt; reportingIds = new HashSet&lt;&gt;();
            HashSet&lt;String&gt; reportedIds = new HashSet&lt;&gt;();
            reportedIdsById.put(id,reportedIds);
            reportingIdsById.put(id,reportingIds);
        }

        for(String reportString : reportHashSet){
            String[] reportIds = reportString.split(&quot; &quot;);
            String reportingId = reportIds[0]; // 신고자ID
            String reportedId = reportIds[1]; // 신고당한ID
            reportedIdsById.get(reportingId).add(reportedId); //신고자별 신고한ID 배열 생성
            reportingIdsById.get(reportedId).add(reportingId); //신고당한ID별 신고자 배열
        }

        for(String id : id_list){
            if( reportingIdsById.get(id).size() &gt;= k ){
                blockedIds.add(id); // 이용정지 당한 ID 배열
            }
        }
        for(int i=0; i&lt;id_list.length;i++){
            String id = id_list[i];
            HashSet&lt;String&gt; intersection = reportedIdsById.get(id);
            intersection.retainAll(blockedIds);
            answer[i]=(intersection.size());
        }

        return answer;
    }
}
</code></pre>
<hr>
<h3 id="결과">결과</h3>
<p>테스트 1 〉    통과 (0.23ms, 73.7MB)
테스트 2 〉    통과 (0.34ms, 76.7MB)
테스트 3 〉    통과 (271.28ms, 201MB)
테스트 4 〉    통과 (0.44ms, 73.7MB)
테스트 5 〉    통과 (0.45ms, 79.3MB)
테스트 6 〉    통과 (5.79ms, 81.1MB)
테스트 7 〉    통과 (9.96ms, 87.4MB)
테스트 8 〉    통과 (13.44ms, 102MB)
테스트 9 〉    통과 (116.98ms, 142MB)
테스트 10 〉    통과 (183.17ms, 131MB)
테스트 11 〉    통과 (303.54ms, 218MB)
테스트 12 〉    통과 (1.50ms, 75.1MB)
테스트 13 〉    통과 (1.08ms, 75.1MB)
테스트 14 〉    통과 (130.13ms, 137MB)
테스트 15 〉    통과 (127.13ms, 162MB)
테스트 16 〉    통과 (0.91ms, 69.1MB)
테스트 17 〉    통과 (1.77ms, 83.1MB)
테스트 18 〉    통과 (2.04ms, 75.5MB)
테스트 19 〉    통과 (2.96ms, 72.2MB)
테스트 20 〉    통과 (81.76ms, 137MB)
테스트 21 〉    통과 (125.73ms, 164MB)
테스트 22 〉    통과 (0.19ms, 70.1MB)
테스트 23 〉    통과 (0.20ms, 76.4MB)
테스트 24 〉    통과 (0.24ms, 80.4MB)</p>
<hr>
<h3 id="다시보기">다시보기</h3>
<hr>
<h3 id="문제참고용">문제(참고용)</h3>
<h4 id="문제설명">문제설명</h4>
<blockquote>
</blockquote>
<p>신입사원 무지는 게시판 불량 이용자를 신고하고 처리 결과를 메일로 발송하는 시스템을 개발하려 합니다. 무지가 개발하려는 시스템은 다음과 같습니다.</p>
<blockquote>
</blockquote>
<p>각 유저는 <strong>한 번에 한 명의 유저를 신고</strong>할 수 있습니다.
<strong>신고 횟수에 제한은 없습니다.</strong> 서로 다른 유저를 계속해서 신고할 수 있습니다.
한 유저를 여러 번 신고할 수도 있지만, <strong>동일한 유저에 대한 신고 횟수는 1회로 처리</strong>됩니다.
k번 이상 신고된 유저는 게시판 이용이 정지되며, 해당 유저를 신고한 모든 유저에게 정지 사실을 메일로 발송합니다.
유저가 신고한 모든 내용을 취합하여 마지막에 한꺼번에 게시판 이용 정지를 시키면서 정지 메일을 발송합니다.</p>
<blockquote>
</blockquote>
<p>다음은 전체 유저 목록이 [&quot;muzi&quot;, &quot;frodo&quot;, &quot;apeach&quot;, &quot;neo&quot;]이고, k = 2(즉, 2번 이상 신고당하면 이용 정지)인 경우의 예시입니다.</p>
<blockquote>
</blockquote>
<table>
<thead>
<tr>
<th>유저 ID</th>
<th>유저가 신고한 ID</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>&quot;muzi&quot;</td>
<td>&quot;frodo&quot;</td>
<td>&quot;muzi&quot;가 &quot;frodo&quot;를 신고했습니다.</td>
</tr>
<tr>
<td>&quot;apeach&quot;</td>
<td>&quot;frodo&quot;</td>
<td>&quot;apeach&quot;가 &quot;frodo&quot;를 신고했습니다.</td>
</tr>
<tr>
<td>&quot;frodo&quot;</td>
<td>&quot;neo&quot;</td>
<td>&quot;frodo&quot;가 &quot;neo&quot;를 신고했습니다.</td>
</tr>
<tr>
<td>&quot;muzi&quot;</td>
<td>&quot;neo&quot;</td>
<td>&quot;muzi&quot;가 &quot;neo&quot;를 신고했습니다.</td>
</tr>
<tr>
<td>&quot;apeach&quot;</td>
<td>&quot;muzi&quot;</td>
<td>&quot;apeach&quot;가 &quot;muzi&quot;를 신고했습니다.</td>
</tr>
</tbody></table>
<blockquote>
</blockquote>
<p>각 유저별로 신고당한 횟수는 다음과 같습니다.</p>
<blockquote>
</blockquote>
<table>
<thead>
<tr>
<th>유저 ID</th>
<th>신고당한 횟수</th>
</tr>
</thead>
<tbody><tr>
<td>&quot;muzi&quot;</td>
<td>1</td>
</tr>
<tr>
<td>&quot;frodo&quot;</td>
<td>2</td>
</tr>
<tr>
<td>&quot;apeach&quot;</td>
<td>0</td>
</tr>
<tr>
<td>&quot;neo&quot;</td>
<td>2</td>
</tr>
<tr>
<td>위 예시에서는 2번 이상 신고당한 &quot;frodo&quot;와 &quot;neo&quot;의 게시판 이용이 정지됩니다. 이때, 각 유저별로 신고한 아이디와 정지된 아이디를 정리하면 다음과 같습니다.</td>
<td></td>
</tr>
</tbody></table>
<blockquote>
</blockquote>
<table>
<thead>
<tr>
<th>유저 ID</th>
<th>유저가 신고한 ID</th>
<th>정지된 ID</th>
</tr>
</thead>
<tbody><tr>
<td>&quot;muzi&quot;</td>
<td>[&quot;frodo&quot;, &quot;neo&quot;]</td>
<td>[&quot;frodo&quot;, &quot;neo&quot;]</td>
</tr>
<tr>
<td>&quot;frodo&quot;</td>
<td>[&quot;neo&quot;]</td>
<td>[&quot;neo&quot;]</td>
</tr>
<tr>
<td>&quot;apeach&quot;</td>
<td>[&quot;muzi&quot;, &quot;frodo&quot;]</td>
<td>[&quot;frodo&quot;]</td>
</tr>
<tr>
<td>&quot;neo&quot;</td>
<td>없음</td>
<td>없음</td>
</tr>
</tbody></table>
<blockquote>
</blockquote>
<p>따라서 &quot;muzi&quot;는 처리 결과 메일을 2회, &quot;frodo&quot;와 &quot;apeach&quot;는 각각 처리 결과 메일을 1회 받게 됩니다.</p>
<blockquote>
</blockquote>
<p>이용자의 ID가 담긴 문자열 배열 id_list, 각 이용자가 신고한 이용자의 ID 정보가 담긴 문자열 배열 report, 정지 기준이 되는 신고 횟수 k가 매개변수로 주어질 때, 각 유저별로 처리 결과 메일을 받은 횟수를 배열에 담아 return 하도록 solution 함수를 완성해주세요.</p>
<h4 id="제한사항">제한사항</h4>
<blockquote>
</blockquote>
<p>2 ≤ id_list의 길이 ≤ 1,000
1 ≤ id_list의 원소 길이 ≤ 10
id_list의 원소는 이용자의 id를 나타내는 문자열이며 알파벳 소문자로만 이루어져 있습니다.
id_list에는 같은 아이디가 중복해서 들어있지 않습니다.
1 ≤ report의 길이 ≤ 200,000
3 ≤ report의 원소 길이 ≤ 21
report의 원소는 &quot;이용자id 신고한id&quot;형태의 문자열입니다.
예를 들어 &quot;muzi frodo&quot;의 경우 &quot;muzi&quot;가 &quot;frodo&quot;를 신고했다는 의미입니다.
id는 알파벳 소문자로만 이루어져 있습니다.
이용자id와 신고한id는 공백(스페이스)하나로 구분되어 있습니다.
자기 자신을 신고하는 경우는 없습니다.
1 ≤ k ≤ 200, k는 자연수입니다.
return 하는 배열은 id_list에 담긴 id 순서대로 각 유저가 받은 결과 메일 수를 담으면 됩니다.</p>
<h4 id="입출력-예">입출력 예</h4>
<blockquote>
</blockquote>
<table>
<thead>
<tr>
<th>id_list</th>
<th>report</th>
<th>k</th>
<th>result</th>
</tr>
</thead>
<tbody><tr>
<td>[&quot;muzi&quot;, &quot;frodo&quot;, &quot;apeach&quot;, &quot;neo&quot;]</td>
<td>[&quot;muzi frodo&quot;,&quot;apeach frodo&quot;,&quot;frodo neo&quot;,&quot;muzi neo&quot;,&quot;apeach muzi&quot;]</td>
<td>2</td>
<td>[2,1,1,0]</td>
</tr>
<tr>
<td>[&quot;con&quot;, &quot;ryan&quot;]</td>
<td>[&quot;ryan con&quot;, &quot;ryan con&quot;, &quot;ryan con&quot;, &quot;ryan con&quot;]</td>
<td>3</td>
<td>[0,0]</td>
</tr>
</tbody></table>
]]></description>
        </item>
    </channel>
</rss>