Server API의 Request 나 Response 의 String이 모두 영어로 되어 있을 경우에는 문제가 없지만, 에러메세지나 Validation 메세지 등을 한글로 보낼 경우에는 `UTP-8` Encoding 을 사용해야 한다. 그럼 언어를 Character Encoding을 설정하는 방법에 대해서 알아보자.
Spring에서 Character Encoding을 설정하기 위해서는 Configuration annotation을 활용하여 Bean으로 Character Encoding Filter를 등록시키면 된다.
내 개인 프로젝트에서는 아래와 같이 간단하게 AppConfig class를 만들어 두었다.
Webserver 개발할 때 Database 나 Redis 등은 필수로 사용하게 된다. 이 때 API로 들어오는 데이터(DTO)를 Database에 저장되는 실제 Model로 복사하는 경우가 매번 발생하게 된다. 이때마다 chain이나 별도 function을 만들어서 복사를 할 수 없다. 왜냐하면 반복해서 넣어야 하는 동일한 코드가 너무 많기 때문이다.
이를 해결하기 위해서 ModelMapper를 사용한다. ObjectMapping을 쉽게 해주는 Library라고 보면 된다.
Applications often consist of similar but different object models, where the data in two models may be similar but the structure and concerns of the models are different. Object mapping makes it easy to convert one model to another, allowing separate models to remain segregated.
ModelMapper의 목적은 아래와 같다.
The goal of ModelMapper is to make object mapping easy, by automatically determining how one object model maps to another, based on conventions, in the same way that a human would - while providing a simple, refactoring-safe API for handling specific use cases.
Object mapping을 자동으로 이름이나 자료형을 가지고 판단하여 수행을 해준다. 반복된 코드를 줄여주기 때문에 효율적이고 휴먼에러는 줄여주는 역할도 한다고 하겠다.
Dependency 추가
ModelMapper를 사용하기 위해서는 우선 Dependecy를 추가한다. 이 글에서는 2.4.4 버전을 사용한다.
Default option으로 사용해도 큰 문제는 없지만, 난 MatchStrategies 를 Strict 하게 하도록 하였고, Null value가 Object에 있어도 Mapping이 되도록 설정하였다.
@Configuration
public class ModelMapperConfig {
@Bean
public ModelMapper modelMapper() {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT).setSkipNullEnabled(true);
return modelMapper;
}
}
Usage
사용방법은 간단하다. 아래의 예제는 ModelMapper object를 사용하였는데 위 설정으로 Bean에 등록을 하였으니 Dependecy Injection 으로 사용해도 된다.
Order & OrderDTO
class Order {
Customer customer;
Address billingAddress;
}
class Customer {
Name name;
}
class Name {
String firstName;
String lastName;
}
class Address {
String street;
String city;
}
class OrderDTO {
String customerFirstName;
String customerLastName;
String billingStreet;
String billingCity;
}
ModelMapper modelMapper = new ModelMapper();
OrderDTO orderDTO = modelMapper.map(order, OrderDTO.class);
위와 같이 2개의 Model이 있고 Order model로 생성된 order object를 사용하여 OrderDTO object를 생성하는 코드이다.
1인 개발을 위해서 환경을 꾸밀 때에는 많은 제약이 있다. 여유 자금이 많아서 서버를 사놓고 VM을 여러 개 설치하여 사용할 수 있겠지만, 난 가난한 가장으로 그러한 환경을 꾸밀 수가 없었다. 사실 현재 밴쿠버에서 유학생으로 있고 집도 좁아서 서버를 설치해 둘 공간도 없긴 하다. 그래서 최근 사양이 좋은 Laptop을 구매하였고 어떻게 개발환경을 꾸밀까 고민을 했었다.
kubernetes를 local로 설치할 경우 다양한 방법이 있다. Linux machine일 경우에는 더 많은 tool들을 사용할 수 있지만, 난 macOS 환경이라 제약이 좀 있었다.
대표적으로 모든 OS 환경에 사용할 수 있는 것이 minikube, kind, k3d, docker desktop kubernetes 등이 있다.
Kubernetes 설치가 아니라 실행이라고 적었다. 사실 이 툴을 이용하여 kubernetes를 설치하는 것이 아니라 실행해야 한다고 하는게 맞을 것 같다. 그만큼 간단하다는 얘기이다.
Settings 메뉴로 들어가면 Kubernetes Menu가 보인다. 클릭해보자.
처음은 `Enable Kubernetes` 가 Check되어 있지 않다. 그것을 체크를 해주고 설치를 하면 몇 분 후에 설치가 완료된다.
현재 나의 환경에는 v1.22.4가 설치되어 있다.
Kubernetes에 접근하기
kubernetes를 설치하고 나면 이제 이 cluster 환경에 접근이 가능해야 한다. 기본적으로 kubernetes의 authentication 정보는 `~/.kube/config` 에 저장이 된다. Docker desktop은 현재 PC를 master node로 하여 설치되므로, 설치가 완료되면 auth 정보가 해당 파일에 자동으로 저장된다. 너무 쉽다.
하지만 cluster 환경에 접근은 authentication으로만은 불가능하다. 기본적인 접근은 `kubectl`이라고 하는 Command Line Interface를 통해서 수행한다. 가장 기본이고 가장 많이 사용하는 것이므로 꼭 기억하자.
kubectl 설치하기
내 환경이 mac이므로 이것을 기준으로 설명하겠다. 나머지는 공식문서 Link로 대신한다.
$ kubectl cluster-info
Kubernetes control plane is running at https://kubernetes.docker.internal:6443
CoreDNS is running at https://kubernetes.docker.internal:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'
오늘은 나의 개발환경의 가장 기본이 되는 kubernetes 설치에 대해서 확인해 보았다.
Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache, and message broker. Redis provides data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes, and streams. Redis has built-in replication, Lua scripting, LRU eviction, transactions, and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster.
오늘은 Redis의 기본적인 개념에 대해서 공부하는 겸 포스트를 적어보도록 하겠다.
우선 Redis는 in-memory data structure store, database, cache, message broker 등으로 사용할 수 있는 open source platform이다.
보통은 memory에 필요한 data를 caching 하여 Database의 접근을 줄여서 service의 속도를 높이기 위해서 사용한다.
저장할 수 있는 data structure로는 String, Hash, List, Set, sorted Set, Bitmap, Hyperloglogs, Geospatial Indexes, Stream 등 다양하다. 그리고 Cluster로 구성하여 Fault tolerance, Preventing diseaster 등을 할 수 있다.
To achieve top performance, Redis works with an in-memory dataset. Depending on your use case, you can persist your data either by periodically dumping the dataset to disk or by appending each command to a disk-based log. You can also disable persistence if you just need a feature-rich, networked, in-memory cache. Redis also supports asynchronous replication, with very fast non-blocking first synchronization, auto-reconnection with partial resynchronization on net split.
Redis는 Top performance를 달성하기 위해 in-memory data set으로 동작된다. 이 말은 service가 중단될 경우 data를 잃어버리게 되는 것이다. 하지만 데이터를 저장하기 위해서 주기적으로 데이터를 disk에 저장하거나 수행되는 각 커맨드를 disk에 log로 남길 수 있다.
그리고, Asyncronous replication을 지원해서 replica 를 생성해 둔다면 불의의 사고로 데이터를 잃어버리는 것을 막을 수 있다.
You can run atomic operations on these types, like appending to a string; incrementing the value in a hash; pushing an element to a list; computing set intersection, union and difference; or getting the member with highest ranking in a sorted set.
그리고 중요한 부분! Redis는 Atomic operation을 보장한다. 이 얘기는 여러 유저가 동시에 같은 정보를 업데이트 하더라도 손실되는 정보가 없다는 얘기이다. 예를 들면 2명의 유저가 동시에 `count` 를 증가시킨다고 할 때 완전 동시에 업데이트시 count는 1개만 증가할 수 있는 경우가 발생될 수 있을 것이다. 하지만 Atomic operation이 보장된다면 count는 2가 증가된다.