溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何使用Ignite+SpringCloud+Docker創(chuàng)建REST應(yīng)用

發(fā)布時(shí)間:2021-12-13 13:52:19 來源:億速云 閱讀:160 作者:iii 欄目:大數(shù)據(jù)

這篇文章主要介紹“如何使用Ignite+SpringCloud+Docker創(chuàng)建REST應(yīng)用”,在日常操作中,相信很多人在如何使用Ignite+SpringCloud+Docker創(chuàng)建REST應(yīng)用問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”如何使用Ignite+SpringCloud+Docker創(chuàng)建REST應(yīng)用”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!

本文將講解基于Spring Cloud和Ignite的RESTful Web服務(wù)的創(chuàng)建過程。該服務(wù)是將Ignite用作為高性能內(nèi)存數(shù)據(jù)庫的容器化應(yīng)用,使用HashiCorp Consul進(jìn)行服務(wù)發(fā)現(xiàn),并通過Spring Data存儲(chǔ)庫抽象與Ignite集群進(jìn)行交互,容器化通過Docker實(shí)現(xiàn)。

配置和啟動(dòng)

配置Consul服務(wù)注冊(cè)

為了方便起見,可以使用Consul的官方Docker鏡像(需要先安裝Docker):

啟動(dòng)Consul的Docker鏡像:

docker run -d -p 8500:8500 -p 8600:8600/udp --name=consul consul agent -server -ui -node=server-1 -bootstrap-expect=1 -client=0.0.0.0

創(chuàng)建一個(gè)基本的Spring Cloud應(yīng)用

創(chuàng)建該應(yīng)用可以從https://start.spring.io入手。

這里需要Spring Web和Spring Consul Discovery模塊,Spring Web是創(chuàng)建REST應(yīng)用的最簡(jiǎn)單的框架之一,Spring Consul Discovery可以將多個(gè)Spring應(yīng)用實(shí)例組合成一個(gè)服務(wù)。

![](https://www.gridgain.com/sites/default/files/inline-images/image1.pn

  • 通過Spring Initializr配置項(xiàng)目(如上圖所示);

  • 點(diǎn)擊Generate按鈕,然后會(huì)下載包含項(xiàng)目工程的壓縮包;

  • 使用某個(gè)IDE打開該壓縮包;

  • (可選)將application.properties文件替換為application.yml,當(dāng)然可以繼續(xù)使用屬性文件格式,但是本文后續(xù)會(huì)使用YAML格式。

application.yml中,為Sprint Cloud添加了基本的參數(shù),給應(yīng)用命名并啟用了Consul服務(wù)發(fā)現(xiàn):

spring:
  application:
    name: myapp
    instance_id: 1
  cloud:
    consul:
      enabled: true
    service-registry:
      enabled: true

添加Ignite依賴

可以從Maven中央倉庫獲得Ignite的最新版本,然后將其添加到構(gòu)建配置文件中:

implementation 'org.apache.ignite:ignite-spring-data_2.2:2.8.1'
compile group: 'org.apache.ignite', name: 'ignite-core', version: '2.8.1'
implementation 'org.apache.ignite:ignite-spring-boot-autoconfigure-ext:1.0.0'

配置Ignite節(jié)點(diǎn)發(fā)現(xiàn)

如何使Ignite節(jié)點(diǎn)相互發(fā)現(xiàn)呢?Ignite具有一個(gè)IpFinder組件,該組件用于處理節(jié)點(diǎn)的注冊(cè)和發(fā)現(xiàn),更多的細(xì)節(jié)信息,請(qǐng)參見Ignite的文檔。

為了集成IpFinder和Consul服務(wù)注冊(cè),需要使用Spring Cloud Discovery模塊,可以將模塊與大量發(fā)現(xiàn)服務(wù)一起使用(例如Zookeeper)。

對(duì)于HashiCorp Consul,有一個(gè)簡(jiǎn)單的IpFinder實(shí)現(xiàn),但是在GitHub上有許多IpFinder的第三方實(shí)現(xiàn)。

配置Spring Cloud和Ignite

因?yàn)槭褂昧薎gnite的自動(dòng)配置模塊,所以配置是一個(gè)相對(duì)簡(jiǎn)單的過程,將以下內(nèi)容放入application.yml文件中:

ignite:
  workDirectory: /opt/ignite/

Ignite將其數(shù)據(jù)存儲(chǔ)在工作目錄中。

現(xiàn)在需要添加對(duì)Ignite Spring Data存儲(chǔ)庫的支持。添加支持的方法之一是通過Java的Configuration:只需添加一個(gè)EnableIgniteRepositories注解,并將存儲(chǔ)庫軟件包作為參數(shù)即可:

@Configuration
@EnableIgniteRepositories(value = "com.github.sammyvimes.bootnite.repo")
public class IgniteConfig {

}

在編譯應(yīng)用之前,需要解決一些問題。Ignite不支持Spring Data的H2版本。因此必須在構(gòu)建配置中重置H2的版本(無論是Gradle還是Maven):

ext {
        set('h3.version', '1.4.197')
 }

另外,Spring Cloud Consul和hystrix還有已知的問題,因此需要將其排除:

implementation ('org.springframework.cloud:spring-cloud-starter-consul-discovery') {
        exclude group: 'org.springframework.cloud', module: 'spring-cloud-netflix-hystrix'
 }

最后,關(guān)于Spring Data BeanFactory,還有一個(gè)問題:BeanFactory會(huì)查找一個(gè)名為igniteInstance的bean,而自動(dòng)配置則提供一個(gè)名為ignite的bean,后續(xù)會(huì)解決這個(gè)問題。

但是現(xiàn)在,需要對(duì)配置類做如下的修改來解決BeanFactory的問題:

@Configuration
@EnableIgniteRepositories(value = "com.github.sammyvimes.bootnite.repo")
public class IgniteConfig {


@Bean(name = "igniteInstance")
    public Ignite igniteInstance(Ignite ignite) {
        ignite.active(true);
        return ignite;
    }

}

創(chuàng)建Ignite的Spring Data存儲(chǔ)庫和服務(wù)

下面會(huì)創(chuàng)建一個(gè)基于Ignite Spring Data存儲(chǔ)庫的CRUD服務(wù)。

下面會(huì)從最常見的示例開始,即Employee類:

public class Employee implements Serializable {

    private UUID id;

    private String name;

    private boolean isEmployed;

        // constructor, getters & setters
}

定義數(shù)據(jù)模型之后,就要添加配置器bean:

@Bean
    public IgniteConfigurer configurer() {
        return igniteConfiguration -> {
            CacheConfiguration cache = new CacheConfiguration("employeeCache");
            cache.setIndexedTypes(UUID.class, Employee.class);

            igniteConfiguration.setCacheConfiguration(cache);
        };
    }

這樣當(dāng)應(yīng)用啟動(dòng)后,會(huì)部署employeeCache緩存,該緩存包含可加快對(duì)Employee實(shí)體查詢的索引。

接下來,與其他Spring Data存儲(chǔ)服務(wù)一樣,需要?jiǎng)?chuàng)建一個(gè)存儲(chǔ)庫和一個(gè)服務(wù):

@Repository
@RepositoryConfig(cacheName = "employeeCache")
public interface EmployeeRepository
        extends IgniteRepository<Employee, UUID> {
    Employee getEmployeeById(UUID id);
}

注意RepositoryConfig注解,其將存儲(chǔ)庫鏈接到即將使用的緩存,之前已經(jīng)使用employeeCache字符串作為名字創(chuàng)建了一個(gè)緩存。

接下來是一個(gè)使用該存儲(chǔ)庫的簡(jiǎn)單服務(wù):

@Service
@Transactional
public class EmployeeService {

    private final EmployeeRepository repository;

    // constructor injection FTW
    public EmpoyeeService(final EmployeeRepository repository) {
        this.repository = repository;
    }

    public List<Employee> findAll() {
        return StreamSupport.stream(repository.findAll().spliterator(), false)
                .collect(Collectors.toList());
    }

    public Employee create(final String name) {
        final Employee employee = new Employee();
        final UUID id = UUID.randomUUID();
        employee.setId(id);
        employee.setEmployed(true);
        employee.setName(name);
        return repository.save(id, employee);
    }
}

這里有2個(gè)方法,createfindAll,用于演示Ignite和Spring Data的集成。

配置REST控制器

下面會(huì)配置一些端點(diǎn),以便可以訪問和修改數(shù)據(jù),一個(gè)簡(jiǎn)單的控制器就可以了:

@RestController
@RequestMapping("/employee")
public class EmployeeController {

    private final EmpoyeeService service;

    public EmployeeController(final EmployeeService service) {
        this.service = service;
    }

    @GetMapping
    public ResponseEntity<List<Employee>> employees() {
        return ResponseEntity.ok(service.findAll());
    }

    @PostMapping
    public ResponseEntity<Employee> create(@RequestParam final String name) {
        return ResponseEntity.ok(service.create(name));
    }

}

這樣,這個(gè)應(yīng)用就開發(fā)完了。

現(xiàn)在就可以啟動(dòng)應(yīng)用,通過向/employee發(fā)送POST請(qǐng)求來創(chuàng)建數(shù)據(jù),并通過發(fā)送GET請(qǐng)求來查詢數(shù)據(jù)。

雖然這個(gè)應(yīng)用性能很高,但是分布式存儲(chǔ)的優(yōu)勢(shì)在哪里呢?

在Docker中部署應(yīng)用

可以通過Docker來創(chuàng)建和管理應(yīng)用節(jié)點(diǎn)。

首先在工程的根目錄,為應(yīng)用創(chuàng)建一個(gè)Dockerfile:

FROM adoptopenjdk:8-jre-hotspot
RUN mkdir /opt/app && mkdir /opt/ignite
COPY build/libs/bootnite-0.0.1-SNAPSHOT.jar /opt/app/app.jar
CMD ["java", "-jar", "/opt/app/app.jar"]

簡(jiǎn)單地說:獲取OpenJDK,為應(yīng)用創(chuàng)建目錄,往鏡像中復(fù)制應(yīng)用的二進(jìn)制文件,并創(chuàng)建默認(rèn)命令以啟動(dòng)應(yīng)用。

現(xiàn)在,在工程的根目錄中,運(yùn)行gradle builddocker build -t ignite-test-app:0.1 -f .dockerfile

接下來,通過Docker,同時(shí)啟動(dòng)應(yīng)用的兩個(gè)實(shí)例。

通過編寫了以下shell腳本,可以幫助啟動(dòng)節(jié)點(diǎn):

MacOS:

export HOST_IP=$(ipconfig getifaddr en0)
docker run -P -e HOST_IP=${HOST_IP} -e DISCO_PORT=$2 -p $2:47500 --name $1 ignition

Linux:

export HOST_IP=$(ip -4 addr show docker0 | grep -Po 'inet \K[\d.]+')
docker run -P -e HOST_IP=${HOST_IP} -e DISCO_PORT=$2 -p $2:47500 --name $1 ignition

在這里所做的是獲取主機(jī)IP地址,以便可以使用端口轉(zhuǎn)發(fā),并使節(jié)點(diǎn)之間可以相互通信。使用-p參數(shù)為Docker容器創(chuàng)建端口轉(zhuǎn)發(fā)規(guī)則,并使用-e參數(shù)將外部端口的值保存在容器的環(huán)境中,以便稍后可以在如下配置中使用這些值:

spring:
  application:
    name: myapp
    instance_id: 1
  cloud:
    consul:
      enabled: true
      host: ${HOST_IP}
    service-registry:
      enabled: true

ignition:
  disco:
    host: ${HOST_IP}
    port: ${DISCO_PORT}

這里添加了自定義配置參數(shù)ignition.disco.hostignition.disco.port,這些參數(shù)將在自定義IP探測(cè)器中使用。注意還通過添加主機(jī)IP地址來更改Consul的配置。

現(xiàn)在,更改Ignite Java配置后就完成了:

@Bean
    public TcpDiscoveryConsulIpFinder finder(final ConsulDiscoveryClient client,
                                             final ConsulServiceRegistry registry,
                                             final ConsulDiscoveryProperties properties,
                                             @Value("${ignition.disco.host}") final String host,
                                             @Value("${ignition.disco.port}") final int port) {
        return new TcpDiscoveryConsulIpFinder(client, registry, properties, host, port);
    }

    @Bean
    public IgniteConfigurer configurer(final TcpDiscoveryConsulIpFinder finder) {
        return igniteConfiguration -> {
            CacheConfiguration cache = new CacheConfiguration("employeeCache");
            cache.setIndexedTypes(UUID.class, Employee.class);

            igniteConfiguration.setCacheConfiguration(cache);
            final TcpDiscoverySpi tcpDiscoverySpi = new TcpDiscoverySpi();
            tcpDiscoverySpi.setIpFinder(finder);

            igniteConfiguration.setDiscoverySpi(tcpDiscoverySpi);
        };
    }

執(zhí)行下面的測(cè)試,可以看下是否一切正常:

  1. 啟動(dòng)一個(gè)應(yīng)用實(shí)例:./starter/start.sh test1 30000

  2. 將一些數(shù)據(jù)提交到實(shí)例;例如curl -d'name = admin'http:// localhost:32784/employee,不同的容器使用不同的端口;

  3. 通過在終端中執(zhí)行docker ps確定容器的端口轉(zhuǎn)發(fā)規(guī)則(規(guī)則類似于0.0.0.0:32784->8080/tcp),確定要使用的端口;

  4. 啟動(dòng)另一個(gè)節(jié)點(diǎn):./starter/start.sh test2 30001;

  5. 停止第一個(gè)節(jié)點(diǎn)(如果是從終端啟動(dòng)容器,則可以使用Ctrl + c);

  6. 執(zhí)行對(duì)第二個(gè)節(jié)點(diǎn)的GET請(qǐng)求,并驗(yàn)證從此請(qǐng)求獲取的數(shù)據(jù)和從第一個(gè)請(qǐng)求獲取的數(shù)據(jù)是否相同:curl http://localhost:32785/employee。

注意,此curl命令中的端口和上一個(gè)curl命令中的端口不相同,因?yàn)閮蓚€(gè)應(yīng)用實(shí)例占用不同的端口。

到此,關(guān)于“如何使用Ignite+SpringCloud+Docker創(chuàng)建REST應(yīng)用”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI