After studying the in-memory data grid, I was wondering what would happen if I actually incorporated it into the app, so I tried to get started.
--A mechanism for distributed management of data on multiple servers. --If all servers can have duplicate data (replication method), flexible data reliability can be ensured by managing duplicate data required only for a certain group of servers (partition method). Can. --Since disk I / O does not occur like DB, you can perform CRUD operations of data and P2P data synchronization at high speed. --Reliable and fast architecture. It seems.
Learn by referring to the following article -Recommended to get an overview -Specific architecture type
――Since I wanted to actually make it after zapping various articles, there is a project called SpringDataGeode
in Spring's git repository, so I will try to experience the in-memory data grid with Spring Boot using it.
--Created assuming a server application that performs user registration and search.
-Create a client / server application template with Spring Initializer.
--Select only Web and lombok.
--This time, create a project with gradle
.
--Added spring-data-geode
to the dependency of build.gradle.
build.gradle
dependencies {
implementation('org.springframework.boot:spring-boot-starter-web'){
//log4j library is spring-data-Excluded because it conflicts with geode's dependent log4j library
exclude group: 'org.springframework.boot', module:'spring-boot-starter-logging'
}
//Add a project that handles domain model as a dependency
compile project(':geodeCommon')
compileOnly('org.projectlombok:lombok')
compile(group: 'org.springframework.data', name: 'spring-data-geode', version: '2.1.3.RELEASE')
}
--Starting class code
GeodeClientApplication.java
package spring.geode.client.geodeClient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.gemfire.config.annotation.ClientCacheApplication;
import org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions;
import org.springframework.data.gemfire.config.annotation.EnablePdx;
import org.springframework.data.gemfire.repository.config.EnableGemfireRepositories;
import spring.geode.client.geodeClient.repository.UserRepository;
import spring.geode.geodeCommon.model.User;
@SpringBootApplication
@ClientCacheApplication(name = "SpringGeodeClientApplication") //①
@EnableGemfireRepositories(basePackageClasses = UserRepository.class) //②
@EnableEntityDefinedRegions(basePackageClasses = User.class) //③
@EnablePdx //④
public class GeodeClientApplication {
public static void main(String[] args) {
SpringApplication.run(GeodeClientApplication.class, args);
}
}
--Explanation of annotation
--①: Setting to start as client application in ʻApache GEODE -②: Setting to make the specified class function as a data accessor of ʻApache GEODE
--③: Setting to automatically create the specified Region (table in RDB)
-④: ʻApache GEODE`'s data serialization / deserialization settings (not required)
--Controller class
UserController.java
package spring.geode.client.geodeClient.controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import lombok.RequiredArgsConstructor;
import spring.geode.client.geodeClient.service.UserService;
import spring.geode.geodeCommon.model.User;
import spring.geode.geodeCommon.model.UserRequest;
@RestController
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
//User search API by name
@RequestMapping(path = "/find/user/{name}", method = RequestMethod.GET)
public User findById(@PathVariable String name) {
return userService.findByName(name);
}
//User all search API
@RequestMapping("/findAll")
public List<User> findAll() {
return userService.findAll();
}
//New user registration API
@RequestMapping(path = "/register/user", method = RequestMethod.POST)
public String register(@RequestBody UserRequest request) {
return userService.register(request).getName();
}
}
--service class
UserService.java
package spring.geode.server.geodeServer.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import spring.geode.geodeCommon.model.User;
import spring.geode.geodeCommon.model.UserRequest;
import spring.geode.server.geodeServer.repository.UserRepository;
@RequiredArgsConstructor
@Service
public class UserService {
private final UserRepository rep;
public User findByName(String name) {
User user=rep.findByName(name).get(0);
return user;
}
public User register(UserRequest request) {
User commited = rep.save(new User(request));
return commited;
}
public List<User> findAll(){
List<User> users=new ArrayList<>();
rep.findAll().forEach(user -> users.add(user));;
return users;
}
}
Repository class
UserRepository.java
package spring.geode.server.geodeServer.repository;
import java.util.List;
import org.springframework.data.gemfire.repository.GemfireRepository;
import spring.geode.geodeCommon.model.User;
public interface UserRepository extends GemfireRepository<User, Integer> {
List<User> findByName(String name);
}
application.properties
spring.data.gemfire.pool.locators=localhost[40404]
server.port=9000
client Set the IP and port of the locator to which the application connects.
This time, specify localhost
to start locator with the server application settings.
ʻThe relationship between client, server and locator in Apache GEODE` is described in the following article. Overview of Apache GEODE
At this point, the client application has been implemented. Since it is necessary to use a common class for the client and server projects, the data objects (User class) to be handled will be aggregated in the Common project and created later.
Except for the startup class, you can bring the client application code into the server application project as it is.
--Startup class
GeodeServerApplication.java
package spring.geode.server.geodeServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.gemfire.config.annotation.CacheServerApplication;
import org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions;
import org.springframework.data.gemfire.config.annotation.EnableLocator;
import org.springframework.data.gemfire.config.annotation.EnableManager;
import org.springframework.data.gemfire.config.annotation.EnablePdx;
import org.springframework.data.gemfire.repository.config.EnableGemfireRepositories;
import spring.geode.geodeCommon.model.User;
import spring.geode.server.geodeServer.repository.UserRepository;
@SpringBootApplication
@CacheServerApplication(locators = "localhost[40404]") //①
@EnableGemfireRepositories(basePackageClasses = UserRepository.class)
@EnableEntityDefinedRegions(basePackageClasses = User.class)
@EnablePdx
public class GeodeServerApplication {
public static void main(String[] args) {
SpringApplication.run(GeodeServerApplication.class, args);
}
@Configuration
@EnableLocator(port = 40404) //②
@EnableManager(start = true) //③
static class LocatorManagerConfiguration {
}
}
--Explanation of annotation
--①: ʻSetting to start as a server application in Apache GEODE. Set the connecting locator to be the 40404 port of
localhost`.
--②: Setting to start locator on 40404 port
--③: Setting to start the service that monitors the client / server application
The implementation of the server application is completed up to this point.
--Request model from client in web app (different from client in ʻApache GEODE`)
UserRequest.java
package spring.geode.geodeCommon.model;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserRequest implements Serializable{
private static final long serialVersionUID = 1L;
private String name;
private int age;
}
--ʻDomain model persisted in Apache GEODE`
User.java
package spring.geode.geodeCommon.model;
import java.io.Serializable;
import java.util.UUID;
import org.springframework.data.gemfire.mapping.annotation.Region;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Region("Users") //①
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private int age;
public User(UserRequest request) {
this.name=request.getName();
this.age=request.getAge();
this.id=UUID.randomUUID().hashCode();
}
}
--Explanation of annotation --①: Set the Region to which this model is associated.
--Since the project that implements the data model depends on the project of the client and server application, the following contents are described in settings.gradle
of the client and server application.
settings.gradle
//geodeCommon should be read as the project name you created
include ':geodeCommon'
project(':geodeCommon').projectDir = new File('../geodeCommon')
At this point, the implementation of the data model is complete.
Since the client application connects to the locator at startup, it is necessary to start the server application first.
--Start server application (embedded Tomacat starts on port number 9090
)
--client application launch (embedded tomcat launches on port number 9000
)
If both applications can be started normally, the client, locator, and server should be connected.
curl -H "Content-Type: application/json" -X POST -d '{"name":"John","age":23}' http://localhost:9000/register/user/;
curl -H "Content-Type: application/json" -X POST -d '{"name":"Bob","age":10}' http://localhost:9000/register/user/;
curl -i http://localhost:9090/findAll
It is OK if the user registered in the client application can be searched in the search results.
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sat, 26 Jan 2019 17:10:37 GMT
[{"id":-1174841827,"name":"Bob","age":10},{"id":-516984913,"name":"John","age":23}]
Just in case, also search by specifying name
curl -i http://localhost:9090/find/user/John;
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sat, 26 Jan 2019 17:12:33 GMT
{"id":-516984913,"name":"John","age":23}
I was able to confirm that the data was synchronized on the client and server. I implemented it with reference to the following official document. https://geode.apache.org/docs/
In the future, I will try to create applications with the peer model, application configuration on AWS, asynchronous persistence, and so on.
Recommended Posts