![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/46rnj/btrveK61bju/RUW46EkmQH06HJzGcXH1yK/img.png)
Kotlin에도 Java 8 Stream과 동일한 지연 계산이 존재하며, Sequence 인터페이스를 활용해서 이를 처리한다. 이에 대해서 간략하게 정리해보려고 한다. 컬렉션 함수를 연쇄할 때, 처리되는 방식 컬렉션 함수의 경우에는 결과 컬렉션을 즉시 생성한다는 특징을 가지고 있다. 따라서 map과 filter를 연쇄해서 처리할 때, 계산 중간 결과를 새로운 컬렉션에 임시로 담는다. 예를 들어 아래와 같은 코드가 있다면, 다음과 같이 처리된다. people.map { it.age }.filter { it >= 30 } 컬렉션의 원소가 적은 경우에는 위와 같이 처리돼도 문제가 없지만, 컬렉션의 원소가 수십만 개에서 수백만 개로 이루어져 있는 경우에는 효율이 떨어지게 된다. 원소가 정말 많은 컬렉션에서 Se..
상황 ioredis 클라이언트를 사용하여, pipeline 기능을 사용하여 Redis Cluster에 Key와 Value를 저장하려고 했는데, 다음과 같은 에러가 발생했다. Error: All keys in the pipeline should belong to the same slots allocation group Redis Cluster를 사용하는 경우, MSET 및 MGET과 같은 멀티 키 명령을 사용할 수 없으며, ioredis 클라이언트에서 제공하는 pipeline의 경우에도 사용할 수 없다. 그래서 위와 같은 에러가 발생하게 되었다. 해결 pipeline을 사용하려면, 같은 슬롯인 경우만 가능하다는 것이다. 그래서 생각한 방법이 10개의 Key를 저장한다고 가정한 상황에서 3개의 슬롯이 존재하..
Docker를 활용해서 Redis Standalone 및 Cluster를 모니터링하고 있는데, 매 번 docker 명령어를 입력해서 해야 하는 번거로움이 있어서 docker-compose.yml 파일로 만들어봤다. version: '3' services: prod-redis-stats: image: insready/redis-stat:latest container_name: prod-redis-stats ports: - '13790:63790' command: [ '--verbose', # 추가 정보 보기 '--server', '127.0.0.1:6379', '127.0.0.2:6379', ] stage-redis-st..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/bPGuHX/btrshAnZh4Z/pQsfs1KhIzcIrOzm9sxAnk/img.png)
Spring MVC의 요청 흐름을 아래의 그림으로 요약할 수 있고, 중간에 중요한 개념들을 정리하려고 한다. DispatcherServlet 프론트 컨트롤러 패턴을 구현할 실체이다. 클라이언트의 모든 Request를 접수하고, 다른 컴포넌트에 역할을 위임한다. 주로 HandlerMapping, HandlerAdapter, ViewResolver로 역할을 위임한다. HandlerMapping 특징 Request의 URL과 매칭 되는 Handler를 선택한다. HandlerMapping 인터페이스를 구현한 여러 구현체들이 있고, 구현체들의 우선순위를 기준으로 매칭 되는 Handler를 선택한다. 여러 구현체들이 있지만, 대표적으로 RequestMappingHandlerMapping과 BeanNameUrlHa..
HttpMessageConverter를 사용하면, JSON 데이터를 Http Message Body에서 직접 읽거나 쓰는 경우에 편리하다. @ResponseBody를 사용하는 경우 ViewResolver 대신에 HttpMessageConverter가 동작된다. 기본 문자 처리의 경우, StringHttpMessageConverter를 사용한다. 기본 객체 처리의 경우, MappingJackson2 HttpMessageConverter를 사용한다. byte [] 처리 및 기타 여러 가지의 HttpMessageConverter가 기본으로 등록되어 있다. HTTP 요청, 응답에 둘 다 사용 요청의 경우, 메시지를 읽어서 객체로 바꾼 다음 컨트롤러에 파라미터로 넘겨주는 역할은 한다. 응답의 경우, 컨트롤러에서 ..
Redis 클라이언트를 통해 Redis에 접속하면, info all의 명령으로 정보를 수집할 수 있는 Redis 자체의 Metric이 있다. Memory used_memory_rss Redis가 현재 사용하고 있는 실제 물리 메모리 양 실제 물리 메모리 사용량이 많으면, Swap이 일어나서 성능이 떨어진다. used_memory 현재 Redis에 할당된(사용하고 있는) 메모리 양 jemalloc의 값을 저장하고 있다가 보여준다. mem_fragmentation_ratio 실제 사용하는 메모리(used_memory)에 비해 Redis가 OS에 할당받은 메모리(used_memory_rss)의 양이 많을 경우, 낭비되는 메모리가 생기고 이러한 경우에 mem_fragmentation_ratio 수치가 올라간다...
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/4ERsk/btrr1NUR1i2/yQqckDlGX8HdTrUPQjLw0k/img.png)
클러스터 특징 1개의 클러스터에는 16,384개의 해시 슬롯을 사용할 수 있다. 16,384개의 해시 슬롯은 샤드로 나눌 수 있다. 최대 500개까지 샤드를 나눌 수 있는데, 제한되는 부분들이 있다. 샤드가 500개인 경우, 복제본 노드는 하나도 생성할 수 없음 샤드가 250개인 경우, 복제본 노드는 0 ~ 1개만 생성할 수 있음 샤드가 166개인 경우, 복제본 노드는 0 ~ 2개만 생성할 수 있음 샤드가 125개인 경우, 복제본 노드는 0 ~ 3개만 생성할 수 있음 샤드가 100개인 경우, 복제본 노드는 0 ~ 4개만 생성할 수 있음 샤드가 83개 이하인 경우, 복제본 노드는 0 ~ 5개를 자유롭게 생성할 수 있음 노드는 Primary와 Replica로 구분된다. 해시 함수는 CRC-16 함수를 사용한..
[ 낙관적 오프라인 잠금 ] 특징 충돌이 감지되면, 트랜잭션을 롤백해 동시 비즈니스 트랜잭션 간의 충돌을 방지한다. 한 세션에서 커밋하려는 변경 내용이 다른 세션의 변경 내용과 충돌하지 않는지 확인하는 방법이다. 세션 간의 충돌 가능성이 낮다고 간주될 때 사용하는 방법이다. 가장 일반적인 구현 방법은 시스템의 각 레코드에 버전 번호를 연결하는 것이다. 세션 데이터에 저장된 버전을 레코드 데이터의 현재 버전과 비교하는 것을 의미한다. 낙관적 오프라인 잠금을 구현하는 데 있어서 버전 번호 대신 수정 타임스탬프를 사용하는 것은 좋지 않다. 시스템 클록은 신뢰할 수 없고, 여러 서버 간에 작업을 조율하는 경우, 더욱 신뢰하기 어렵기 때문이다. 버전 번호를 사용할 때 문제점 일관성 없는 읽기의 문제가 해결되지 않..
Elasticsearch Node의 역할을 설정하지 않고 실행하게 되면, 해당 Node는 Master, Data 역할을 부여받게 됩니다. 이후 elasticsearch.yml 파일을 수정해서 Master 역할만 설정하게 되면, 에러가 발생하게 되고 이를 해결한 과정입니다. elasticsearch.yml 파일을 수정하지 않고, 그대로 실행 첫 번째로 elasticsearch.yml 파일을 수정하지 않고 실행하게 되면, Master 및 Data 역할을 포함한 모든 역할을 맡은 채로 실행됩니다. $ bin/elasticsearch # Elasticsearch Node 실행 elasticsearch.yml 파일에 node.roles를 master로 설정하여 실행 elasticsearch.yml 파일을 아래와 ..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/rWcd2/btrj4WR1c8I/3PdR1SjPktKermj0VfZ0sK/img.png)
Lucene에서 색인을 하는 과정 우선 lucene에서는 크게 다음과 같은 과정으로 색인을 하게 됩니다. Lucene에서는 Index File을 생성할 때, Index File Format인 Segment File을 통해 색인을 하며, Segment File이 생성되면, DocumentWriter를 통해 색인하는 과정이 만들어지고 색인이 완료되면, Commit을 통해 실제 데이터 파일에 쓰입니다. 하나의 Index에는 여러 개의 Segment File이 존재하는데, 여러 개의 Segment File이 Commit이 되면, SegmentMerger를 통해 merge 작업을 수행하는 흐름으로 색인을 하게 됩니다. 여기서 여러 개의 Segment File이 존재하는 이유가 궁금하실 수도 있는데요. 색인이 된 ..