목차
Pivotal Gemfire 다운로드 및 설치, 기본 설정
Spring Boot를 이용한 Gemfire 이용
지난시간에 이어서 간단한 테스트용 Region 생성과 Data 를 Region 안에 넣고 빼는 샘플 프로젝트를 제작해보자.
완성된 소스는 여기서 확인 가능하다.
https://github.com/Park-jihoon/gemfire-demo
Region 생성 우선 gfsh 를 이용해 region 을 생성하자. region은 일반적인 DataBase로 치면 Table과 비슷한 역할을 하는 것으로 생성 시 많은 옵션을 줄 수 있다.
생성시 옵션은 대략 아래와 같다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 create region --name=value [--type =value] [--template-region=value] [--groups=value(,value)*] [--if -not-exists(=value)?] [--key-constraint=value] [--value-constraint=value] [--enable -statistics=value] [--entry-idle-time-expiration=value] [--entry-idle-time-expiration-action=value] [--entry-time-to-live-expiration=value] [--entry-time-to-live-expiration-action=value] [--entry-idle-time-custom-expiry=value] [--entry-time-to-live-custom-expiry=value] [--region-idle-time-expiration=value] [--region-idle-time-expiration-action=value] [--region-time-to-live-expiration=value] [--region-time-to-live-expiration-action=value] [--disk-store=value] [--enable -synchronous-disk=value] [--enable -async-conflation=value] [--enable -subscription-conflation=value] [--cache-listener=value(,value)*] [--cache-loader=value] [--cache-writer=value] [--async-event-queue-id=value(,value)*] [--gateway-sender-id=value(,value)*] [--enable -concurrency-checks=value] [--enable -cloning=value] [--concurrency-level=value] [--colocated-with=value] [--local -max-memory=value] [--recovery-delay=value] [--redundant-copies=value] [--startup-recovery-delay=value] [--total-max-memory=value] [--total-num-buckets=value] [--compressor=value] [--off-heap(=value)] [--partition-resolver=value] [--eviction-entry-count=value] [--eviction-max-memory=value] [--eviction-action=value] [--eviction-object-sizer=value]
우선 region 생성 시 필수값인 name과 type만 살펴보자.
name
region을 해당 값의 이름으로 생성한다.
DB의 tableName과 유사
type
PARTITION, PARTITION_REDUNDANT, REPLICATE, LOCAL, etc.
region type 에 따라 많은 타입이 존재하며 원하는 형태의 저장타입을 지정하면 된다.
이번 샘플에서는 아래의 두가지 region만 생성해본다.
1 2 3 4 5 6 7 8 9 10 11 12 gfsh>create region --name=testCache --type =REPLICATE Member | Status | Message ------- | ------ | ---------------------------------------- server1 | OK | Region "/testCache" created on "server1" Cluster configuration for group 'cluster' is updated. gfsh>create region --name=customer --type =REPLICATE Member | Status | Message ------- | ------ | --------------------------------------- server1 | OK | Region "/customer" created on "server1" Cluster configuration for group 'cluster' is updated.
Spring Boot Sample 생성
환경
java 1.8 이상
Maven
Spring boot 2.1.1.RELEASE
Spring geode starter 1.2.1.RELEASE
SpringFox Swagger 2.9.2
Directory 구조 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Gemfire-demo |-- pom.xml `-- src `-- main `-- java `-- ko.co.pohinian.gemfiredemo |-- GemfireDemoApplication.java |-- configuration | |-- GemfireConfiguration.java | `-- SwaggerConfiguration.java |-- controller | |-- CustomerController.java | `-- TestCacheController.java |-- entity | |-- Customer.java | `-- TestCache.java |-- repository | `-- CustomerRepository.java `-- service `-- TestCacheService.java
파일 설명 pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 <parent > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > 2.2.1.RELEASE</version > <relativePath /> </parent > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.geode</groupId > <artifactId > spring-geode-starter</artifactId > <version > 1.2.1.RELEASE</version > </dependency > <dependency > <groupId > io.springfox</groupId > <artifactId > springfox-swagger2</artifactId > <version > 2.9.2</version > </dependency > <dependency > <groupId > io.springfox</groupId > <artifactId > springfox-swagger-ui</artifactId > <version > 2.9.2</version > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <optional > true</optional > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > <exclusions > <exclusion > <groupId > org.junit.vintage</groupId > <artifactId > junit-vintage-engine</artifactId > </exclusion > </exclusions > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <scope > test</scope > </dependency > </dependencies >
geode와 swagger2 관련 라이브러리는 버전을 명시해야 한다.
GemfireDemoApplication.java 실행을 위한 클래스를 생성한다.
1 2 3 4 5 6 @SpringBootApplication public class GemfireDemoApplication { public static void main (String[] args) { SpringApplication.run(GemfireDemoApplication.class , args ) ; } }
GemfireConfiguration.java
gemfire를 사용하기 위한 설정을 모아두는 클래스 입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Configuration @EnableGemfireCaching public class GemfireConfiguration { @Bean public ClientCache gemfireCache () { ClientCacheFactory cacheFactory = new ClientCacheFactory(); cacheFactory.addPoolLocator("192.168.0.6" , 10334 ); return cacheFactory.create(); } @Bean ("testCache" ) public ClientRegionFactoryBean<String, TestCache> testCache (@Autowired ClientCache clientCache) { ClientRegionFactoryBean<String, TestCache> regionFactoryBean = new ClientRegionFactoryBean<>(); regionFactoryBean.setCache(clientCache); regionFactoryBean.setClose(false ); regionFactoryBean.setShortcut(ClientRegionShortcut.PROXY); return regionFactoryBean; } @Bean ("customer" ) public ClientRegionFactoryBean<Long, Customer> customer (@Autowired ClientCache clientCache) { ClientRegionFactoryBean<Long, Customer> regionFactoryBean = new ClientRegionFactoryBean<>(); regionFactoryBean.setCache(clientCache); regionFactoryBean.setClose(false ); regionFactoryBean.setShortcut(ClientRegionShortcut.PROXY); return regionFactoryBean; } }
@EnableGemfireCaching 으로 gemfire cache를 사용할 것임을 명시한다.
gemfireCache()에서 연결하기위한 Gemfire 서버의 정보를 설정한다.
192.168.0.6은 이전 글에서 시작한 locator 정보의 ip이다.
기본 local 접속이기때문에 별도의 username 과 password 는 설정하지 않는다. 하지만 별도의 서버를 구성할 경우에는 서버의 gemfire username과 password를 추가해야 한다.
customer와 testCache는 동명의 region에 대한 정보를 입력한다.
ClientRegionShortcut.PROXY는 애플리케이션에서 저장되는 정보를 어떠한 방식으로 처리할지를 지정하는 것으로 기본값음 LOCAL이다. LOCAL인 경우 값을 애플리케이션에서만 가지고 있게 되며 서버로 전송하지 않는다.
별도의 서버를 두고 데이터를 공유할 경우에는 PROXY로 지정해줘야 한다.
Customer 저장 및 로드 Customer 는 org.springframework.data.repository.CrudRepository를 사용하여 데이터를 저장 및 삭제하는 예제다.
Customer.java region 정보를 명시해주는 클래스다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Data @ToString @Region ("customer" )@NoArgsConstructor @RequiredArgsConstructor (staticName = "newCustomer" )public class Customer implements Serializable { @Id @NonNull @Getter private Long id; @NonNull @Getter private String name; }
Serializable은 java 끼리만 gemfire의 데이터를 공유할 경우에 사용하면 간편하다. 다만 다른 언어들과 데이터를 공유할 경우에는 DataSerializable 등을 구현하여줘야 한다.
CustomerRepository.java
1 2 public interface CustomerRepository extends CrudRepository <Customer , Long > {}
Customer의 ID 타입인 Long 을 명시해준다. gemfire 이외의 기술을 선택할 경우를 대비해 유연하도록 CrudRepository를 구현해준다. findByName 등 jpa 에서 사용하던 형태의 메서드를 선언해 사용 가능하다.
CustomerController.java
Customer 의 정보를 저장하기 위한 Rest Controller 이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @RestController @RequestMapping ("customer" )public class CustomerController { private final CustomerRepository customerRepository; public CustomerController (CustomerRepository customerRepository) { this .customerRepository = customerRepository; } @PostMapping ("{key}" ) public Customer put (@PathVariable("key" ) Long key, @RequestBody String name) { Customer customer = Customer.newCustomer(key, name); return customerRepository.save(customer); } @GetMapping ("{key}" ) public Customer get (@PathVariable("key" ) Long key) { return customerRepository.findById(key).orElse(new Customer()); } }
@RestController는 RestApi로 사용하기 위해 선언한다.CustomerRepository의 Save 및 findById를 사용한다.
save와 findById는 자동으로 생성된다.Customer.newCustomer(key, name) 입력된 값으로 저장을 위한 신규 객체를 생성한다.orElse(new Customer()) 값이 존재하지 않을 경우 빈 객체를 리턴한다.
Customer 테스트
1 2 3 4 5 > curl -X POST "http://localhost:8080/customer/1" -H "accept: */*" -H "Content-Type: application/json" -d "테스트" { "id" : 1, "name" : "테스트" }
1 2 3 4 5 > curl -X GET "http://localhost:8080/customer/1" -H "accept: */*" { "id" : 1, "name" : "테스트" }
1 2 3 4 5 6 7 8 9 10 11 12 gfsh>describe region --name=customer Name : customer Data Policy : replicate Hosting Members : server1 Non-Default Attributes Shared By Hosting Members Type | Name | Value ------ | ----------- | --------------- Region | data-policy | REPLICATE | size | 1 | scope | distributed-ack
TestCache 저장 및 로드 TestCache는 org.springframework.cache를 이용해 최소한의 설정값 만으로 Gemfire를 사용하기 위한 예제이다.
TestCache.java
TestCache는 일반적인 java entity 파일이다. 별도의 gemfire를 위한 설정은 존재하지 않는다.
1 2 3 4 5 6 7 @Data @EqualsAndHashCode @ToString public class TestCache implements Serializable { private String name; private String addr; }
TestCacheService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 @Service public class TestCacheService { @CachePut (cacheNames = "testCache" , key = "#key" ) public TestCache put (String key, TestCache testCache) { return testCache; } @Cacheable (cacheNames = "testCache" , key = "#key" ) public TestCache get (String key) { return null ; } }
@CachePut, @Cacheable 등 Spring Cache 를 이용해 Gemfire 의 Region에 데이터를 저장 및 로드 가능하다. 반드시 @Service 레벨이어야 한다. 또한, proxy 패턴을 이용하는 것이므로 같은 Class 내부에서 호출하는 부분은 캐싱되지않는다.cacheNames = "testCache" 으로 region의 이름을 명시한다.key = "#key"와 같이 매개변수명을 조합해 key를 지정할 수 있다.
TestCacheController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @RestController @RequestMapping ("cache" )public class TestCacheController { private final TestCacheService testCacheService; public TestCacheController (TestCacheService testCacheService) { this .testCacheService = testCacheService; } @PostMapping ("{key}" ) public TestCache put (@PathVariable("key" ) String key, @RequestBody TestCache value) { return testCacheService.put(key, value); } @GetMapping ("{key}" ) public TestCache get (@PathVariable("key" ) String key) { return testCacheService.get(key); } }
TestCacheService를 이용해 데이터를 저장 및 로드 한다.
TestCache 테스트
1 2 3 4 5 > curl -X POST "http://localhost:8080/cache/1" -H "accept: */*" -H "Content-Type: application/json" -d "{ \"addr\": \"테스트주소\", \"name\": \"테스트이름\"}" { "name" : "테스트이름" , "addr" : "테스트주소" }
1 2 3 4 5 curl -X GET "http://localhost:8080/cache/1" -H "accept: */*" { "name" : "테스트이름" , "addr" : "테스트주소" }
1 2 3 4 5 6 7 8 9 10 11 12 gfsh>describe region --name=testCache Name : testCache Data Policy : replicate Hosting Members : server1 Non-Default Attributes Shared By Hosting Members Type | Name | Value ------ | ----------- | --------------- Region | data-policy | REPLICATE | size | 1 | scope | distributed-ack
저장된 것을 확인할 수 있다.
참고