无服务器应用架构的入门

243 阅读14分钟

{{公告正文}}

{{announcement.title}}

DZone>Refcardz>无服务器应用架构入门

refcard cover

参考资料#379

无服务器应用架构入门

无服务器模式可以将技术团队从较为单调的开发工作中解放出来,使他们能够专注于创新。而使用无服务器数据库来构建云原生应用,可以放大这种优势,因为它有能力进行扩展,而不会受到独立部署的服务中的零散数据的阻碍。

本参考卡直接探讨了构建无服务器的Java Web应用。你会发现遵循教程所需的工具清单,以及全面的分步说明、代码片段和无服务器应用程序样本的配套资源库。

易于参考的免费PDF

为您带来的是

Cockroach Labs

refcard cover

撰稿人

author avatar丹-凯利高级

技术内容营销经理,Cockroach Labs

目录

介绍 ►何时使用无服务器数据库进行构建 ► 构建一个无服务器应用示例 ► 结论

第一节

简介

在您将双手伸入土壤之前,有必要回顾一下 "无服务器 "的实际含义。当然,服务器在无服务器计算中仍然存在;在无服务器架构中,DevOps团队不必担心构建、配置和管理硬件的问题。而对于开发者来说,无服务器意味着他们可以与数据库进行沟通,就像云环境中的一个API端点一样。所有这些都是说。"无服务器 "消除了应用架构的维护,从而为创新创造了更多空间。

本参考卡的意图是,通过直接跳入构建无服务器Java Web应用的实践教程,帮助你轻松地开始使用无服务器应用架构。

第二节

何时使用无服务器数据库进行构建

几乎所有的现代云原生应用都需要持久的数据存储。然而,在每个服务都独立部署的无服务器架构中,存储数据变得更具挑战性。具体来说,无服务器应用中的事务需要一致性,以便最终能够对其进行调节,但应用也需要有效地扩展,而不被零散的数据所阻碍。基于这些原因,使用无服务器数据库是很重要的,因为它可以为现代应用快速开发可扩展的数据存储。

在下面的教程中,我们将使用CockroachDB无服务器,但也有一些其他的无服务器数据库可用,比如Fauna DB和Amazon Aurora无服务器。CockroachDB很容易与Quarkus一起使用,并提供对Hibernate ORM的支持,由于Panache的存在,Quarkus与Hibernate配合得特别好。要实现无服务器解决方案,你只需要创建集群并将你的应用程序连接到数据库,与你添加任何其他SQL数据库的方式类似。这意味着你可以在几分钟内开始构建你的应用。

第三节

构建一个无服务器应用程序样本

在本教程中,我们将通过创建下图所示的排行榜应用来演示如何构建一个无服务器的Java应用。

图1

首先,我们将使用Quarkus构建该应用的后端,在CockroachDB无服务器上进行CRUD操作,然后用它来存储前端显示的排行榜项目。我们将使用Node.js和React构建前端,使用户能够显示和添加新的排行榜项目。然后,我们将把整个解决方案部署到Heroku,使其在全球范围内可用。

你可以使用GitHub上的配套存储库进行跟踪。例子是在macOS的Visual Studio Code中创建的,但我们在必要时也包括其他操作系统的说明。

注意:我们假设你至少有中级的Java编程技能,并且熟悉Quarkus。如果你对Java中的JPAMVC不熟悉,请查看以下教程。"学习JPA与Hibernate"。

这里有一个你需要的工具清单。

构建应用程序的后端

我们将从创建Quarkus后端开始。让我们进入Quarkus项目生成器,设置我们应用程序的扩展,我们可以把它看作是依赖关系。

组字段中,输入 "org.db"。在Artifact字段中,输入 "cockroach-serverless"。在构建工具栏中,输入 "Maven"。接下来,选择以下四个软件包。

  • RESTEasy Classic
  • RESTEasy Classic JSON-B
  • 用于Hibernate ORM的REST资源与Panache [quarkus-hibernate-orm-rest-data-panache]
  • JDBC驱动 - PostgreSQL [quarkus-jdbc-postgresql]

一旦项目被配置好,选择生成你的应用程序。然后Quarkus显示另一个窗口,你可以在那里下载源代码。

图2

下载zip文件,就可以收到带有静态页面的Java项目,一个index.html 文件(在src/main/resources ),一个REST API,一个GreetingResource.java 文件(在src/main/java/org/db ),一些单元测试,和一些Docker文件。

GreetingResource.java 文件实现了一个简单的/hello 端点,有一个GET 方法,返回静态字符串,Hello RESTEasy

@Path("/hello")
public class GreetingResource {

    @GET
     @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "Hello RESTEasy";
    }
}

要看到这段代码的工作情况,请导航到解压后的文件/path/to/cockroach-serverless/ ,并在终端输入以下命令。

./mvnw quarkus:dev

接下来,使用你的浏览器并导航到localhost:8080 。你会看到index.html 正在被渲染。你可以忽略日志中产生的任何测试输出。

图3

将请求附加到/hello 端点,以看到静态字符串,Hello RESTEasy 。一旦完成这些,我们就可以为我们的排行榜应用程序添加实现实际REST API的类。

src/main/java/org/db 中创建一个名为LeaderboardItem.java 的文件,并添加以下代码。

package org.db;
import javax.enterprise.inject.Produces;
import javax.persistence.Column;
import javax.persistence.Entity;

import io.quarkus.hibernate.orm.panache.PanacheEntity;

@Entity
public class LeaderboardItem extends PanacheEntity {

    @Column
    public String name;

    @Column
    public double points;

}

这将代表排行榜上的项目。LeaderboardItem 类有两个字段:namepoints 。该类派生自PanacheEntity ,所以namepoints 字段的getters和setters将自动生成。此外,PanacheEntity 提供了一个默认的标识符:id ,这有助于保持LeaderboardItem 类的定义干净和简单。

接下来,让我们为排行榜上的项目实现实际的REST资源。在src/main/java/org/db 目录中添加LeaderboardResource.java 类。

package org.db;

import io.quarkus.hibernate.orm.rest.data.panache.PanacheEntityResource;

public interface LeaderboardResource extends PanacheEntityResource
     <LeaderboardItem, Long> {

}

PanacheEntityResource,作为一个基类,是通用的,实现了我们的CRUD操作。它将为LeaderboardItem 的实例工作,并使用默认标识符Long (来自PanacheEntity 类)来识别特定的数据库对象。

还要注意的是,LeaderboardResource 将自动生成REST API端点,并在/leaderboard 路径上暴露。

现在我们准备创建CockroachDB数据库并将其连接到我们的后端。

添加无服务器数据库

如果你没有一个免费的CockroachDB账户,你就需要创建一个。注册后,你会被转到仪表盘。

选择创建集群,在弹出的显示屏上选择无服务器。无服务器选项要求你选择你的云提供商和它的区域。将AWS设置为你的供应商,并使用最接近你的物理位置的区域。你可以选择修改集群的名称,不过我们使用的是默认值:fluffy-possum

选择创建你的免费集群,开始创建集群的过程。几秒钟后,你会看到一个包含你的连接信息的窗口。

图4

在这一点上一定要注意你的数据库密码,因为这是你唯一可以透露密码的地方。否则,你需要使用CockroachDB仪表盘重置密码,在:SQL Users>Action>Change Password.

当你打开这个窗口的时候,你还想再抓取一些数值,你很快就会需要配置application.properties 类。

选择 "仅参数"下拉菜单,注意它所呈现的值(用户名、主机、数据库和端口)。

图5

接下来,打开src/main/resources/application.properties ,输入以下代码。将用户名、密码、主机、端口和数据库替换为CockroachDB Serverless中的值。在JDBC的URL中使用集群的名称。

# configure your datasource
quarkus.datasource.db-kind = postgresql
quarkus.datasource.username = dev
quarkus.datasource.password = <your password>
quarkus.datasource.jdbc.url = jdbc:postgresql://<your host>:26257/<cluster-name>.<your database>

quarkus.hibernate-orm.database.generation = update

现在我们已经准备好测试该应用程序了。在终端中输入以下命令,再次运行该应用程序。

./mvnw quarkus:dev

然后,导航到localhost:8080/leaderboard 。该资源返回一个空集合。我们可以使用curl 添加一个项目。

curl -i -X POST -H "Content-Type:application/json" -d "{  \"name\" : \"Dave\",  \"points\" : \"100\"}" http://localhost:8080/leaderboard

该资源应该以201的HTTP状态代码响应。

图6

该项目被成功地添加到数据库中。我们可以通过发送一个GET 请求到http://localhost:8080/leaderboard ,用curl或网络浏览器来检查。

图7

建立应用程序的前端

后端准备好了,我们来添加前端。因为我们将使用React构建,我们需要确保我们也有Node.js。如果有必要,现在就安装它。

首先,打开你的终端,进入项目的目录。在/src/main 创建一个新的目录,名为webapp 。然后,通过输入以下命令创建React项目。

npx create-react-app src/main/webapp/

图8

输入y 来继续。React网络应用程序将在src/main/webapp 。你可以通过改变你的工作目录到src/main/webapp ,然后输入以下命令来预览该应用程序。

npm start

你会看到下面的欢迎画面。

图9

现在让我们来定制我们的网络应用并添加排行榜。我们将使用PatternFly包来创建该表。通过在src/main/webapp 目录下调用以下命令,安装PatternFlynpm 包。

npm install @patternfly/patternfly –save

然后,在index.js 中导入patternfly.css

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import '@patternfly/patternfly/patternfly.css';

接下来,在webapp/src 目录下创建一个名为components 的子目录。然后,在webapp/src/components ,创建一个leaderboard.jsx 文件并添加以下代码。

import React from 'react'

const Leaderboard = ({ items }) => {
    return (
        <div>
        
             <center><h1>Leaderboard</h1></center>
            <table className="pf-c-table pf-m-grid-md">
                 <thead>
                     <tr role="row">
                         <th role="columnheader">Name</th>
                         <th role="columnheader">Points</th>
                     </tr>
                 </thead>               
                 {items.map((item) => (
                     <tbody role="rowgroup">
                         <tr role="row">
                             <td role="cell">{item.name}</td>
                             <td role="cell">{item.points}</td>
                         </tr>
                     </tbody>
                ))}
             </table>
        </div>

    )
};

export default Leaderboard

这个组件,当给定排行榜项目列表时,将把它们渲染成我们想要显示的两列表格。

图10

为此,Leaderboard 组件在项目集合上进行迭代,并将每个项目显示为一个表格行。现在让我们在App.js 中使用Leaderboard 组件。

import React, {Component} from 'react';
import Leaderboard from './components/leaderboard';

class App extends Component {
  state = {
    items: []
  }
  componentDidMount() {
    fetch('http://localhost:8080/leaderboard')
    .then(res => res.json())
    .then((data) => {
        this.setState({ items: data.sort((a,b)=>{return a.points < b.points}) })
    })
     .catch(console.log)
  }

  render () {
    return (
      <Leaderboard items={this.state.items} />
    );
  }
}

export default App;

App 组件将向我们的Leaderboard 资源发送一个GET 请求,我们已经使用Quarkus REST API实现了这个请求。从API中获取的项目集合被存储在state.items ,然后传递给Leaderboard React 组件。重要的是,这些项目也是按其点数属性降序排序的。

为了使其发挥作用,我们需要配置跨源资源共享(CORS)。默认情况下,前端暴露在localhost ,端口为3000 ,而REST API暴露在端口8080 。这可能会阻止从API获取数据--网络浏览器可能会因为错误配置的CORS而阻止一个请求。

要启用 CORS,请在 Quarkus 项目中的application.properties 添加以下一行。

quarkus.http.cors=true

现在,通过运行./mvnw quarkus:dev ,再次运行REST API项目,并通过运行npm start ,重新启动Web应用程序。然后,打开localhost:3000/leaderboard 。你应该看到像这样的东西。

图11

在这一点上,我们可以使用curl或任何其他REST API客户端添加项目。让我们看看如何做到这一点。

添加项目

现在我们将添加一个表单,使用户能够通过REST API向排行榜添加新条目。该应用程序还将包含两个链接,使用户能够在排行榜表单界面之间切换。

图12

我们首先用react路由器来补充React应用程序。要做到这一点,请安装react-router-dom npm 包。

npm install react-router-dom

然后,在components 目录中,添加一个AddItem.css 文件。

input {
    margin: 5px;
}

接下来,用以下代码实现AddItem.jsx 组件。

import React from 'react';
import './AddItem.css'

class AddItem extends React.Component {
    constructor(props) {
      super(props);
      this.state = { name: '', points: 0 };
    }

    handleChange = (event) => {
       this.setState({[event.target.name]: event.target.value});

       console.log(this.state);
    }

    handleSubmit = (event) => {
       console.log(JSON.stringify(this.state));
      fetch('http://localhost:8080/leaderboard', {
          method: 'POST',          
          body: JSON.stringify(this.state),
          headers: {
            'Content-Type': 'application/json'
          },
         }).then(function(response) {
          return response.json();
        });

       event.preventDefault();
  }

    render() {
      return (        
        <form onSubmit={this.handleSubmit}>
            <input type="text" value={this.state.value}
                        name="name" onChange={this.handleChange} placeholder="Name"/>
             <br/>
            <input type="text" value={this.state.value}
                        name="points" onChange={this.handleChange}placeholder="Points"/>          
             <br/>
            <input type="submit" value="Submit" />
         </form>       
      );
    }
  }

  export default AddItem

AddItem 组件包括一个有两个文本字段的表单。这些文本字段的值被用来更新组件的状态。当用户选择提交按钮时,一个POST 请求被发送到我们的后端。

最后,我们修改App.js ,以包括对LeaderboardAddItem 组件的链接。

import React, {Component} from 'react';
import {BrowserRouter as Router, Routes, Route, Link} from 'react-router-dom'
import Leaderboard from './components/Leaderboard';
import AddItem from './components/AddItem';

class App extends Component {
  state = {
    items: []
  }

  componentDidMount() {
    fetch('http://localhost:8080/leaderboard')
    .then(res => res.json())
    .then((data) => {
      this.setState({ items: data.sort((a,b)=>{return a.points < b.points}) })
    })
     .catch(console.log)
  }

  render () {
    return (
       <Router>
        <div style={{padding: "5px"}}>
     <Link to="/">Leaderboard</Link><br/>
     <Link to="/addItem" >Add item</Link> <br/>
 </div>

        <hr/>

         <Routes>
          <Route exact path='/'
                 element={<Leaderboard items={this.state.items}/>} />
          <Route exact path='/addItem'
                  element={< AddItem />} />
         </Routes>
       </Router>
    );
  }
}

export default App;

现在,再次运行网络应用程序。你可以在排行榜窗口的顶部看到这些链接。

选择添加项目,然后填入表格。

图13

提交表格后,选择Leaderboard并刷新页面,即可看到新的项目。

图14

你也可以使用setInterval JavaScript函数,在预定义的时间间隔内自动刷新排行榜。

部署到Heroku

在本节中,我们将把整个解决方案部署到Heroku,通过独立部署后端和前端,以云原生的方式进行部署。要完成所有的说明,你将需要Heroku和Git账户,以及在你的开发机器上安装Heroku CLI。

要在macOS上安装Heroku CLI,使用brew

brew install heroku/brew/heroku

在Ubuntu上,使用snap

sudo snap install heroku --classic

在其他Linux发行版上,使用一个tarball

在Windows上,使用一个专用的安装程序

后端部署

首先,让我们通过Heroku CLI和Git来部署后端。

首先登录Heroku。

heroku login

然后,用以下配置更新你的application.properties 文件。

quarkus.http.port=${PORT:8080}

这就更新了后端监听请求的HTTP端口,使其与Heroku提供的端口一致。

接下来,创建一个system.properties 文件。

echo "java.runtime.version=11" >> system.properties

我们用它来设置我们的JDK为11版,以匹配Quarkus的配置。

接下来,创建Procfile ,Heroku用它来启动我们的应用程序。

echo "web: java \$JAVA_OPTS -jar target/quarkus-app/quarkus-run.jar" >> Procfile

在创建我们的应用程序之前,我们需要通过Git整理一切。初始化一个本地Git仓库并提交所有这些文件。

git init
git add .
git commit -am "Initial version"

现在,在Heroku上创建应用程序。

heroku create

最后,通过Git进行部署。

git push heroku main

这个命令的输出应该与此类似。

图15

要看到应用程序的运行,请输入heroku open 。这将打开默认的网页浏览器并导航到Heroku应用程序的URL。

图16

在URL上添加/leaderboard ,可以看到后端与CockroachDB的通信,并返回排行榜项目的列表。请注意,这个列表与我们之前的一致,因为数据是从同一个数据库中获取的。

图17

前端部署

在确保后端工作后,让我们来部署前端。我们首先用Heroku应用程序的URL来更新代码。在我们的例子中,它是https://afternoon-fortress-35863.herokuapp.com/leaderboard 。你的URL将是类似的。

用你的URL更新App.js 文件的这一部分--在src/main/webapp/src

componentDidMount() {
  fetch('https://afternoon-fortress-35863.herokuapp.com/leaderboard')
  .then(res => res.json())
  .then((data) => {
    this.setState({ items: data.sort((a,b)=>{return a.points < b.points}) })
  })
  .catch(console.log)
}

然后,在src/main/webapp/src/components 中更新AddItem.jsx 文件中的URL。

handleSubmit = (event) => {
   console.log(JSON.stringify(this.state));
  fetch('https://afternoon-fortress-35863.herokuapp.com/leaderboard', {
      method: 'POST',
      body: JSON.stringify(this.state),
      headers: {
        'Content-Type': 'application/json'
      },
     }).then(function(response) {
      return response.json();
    });

   event.preventDefault();
}

在继续进行之前,让我们确保一切都在本地运行。将你的工作目录改为src/main/webapp ,然后使用npm start 。然后,进入localhost:3000 。注意,检索排行榜项目的时间可能比以前长。现在,我们准备将前端部署到Heroku。

首先创建Procfile

echo "web: npm start" >> Procfile

现在,初始化另一个资源库。添加并提交所有文件,确保从src/main/webapp 子目录中进行。

git init
git add .
git commit -am "webapp"

创建新的Heroku应用程序。

heroku create

最后,通过Git部署前端。

git push heroku main

现在要做的就是打开你的应用程序。

heroku open

你应该看到解决方案已经启动并运行。

图18

尝试添加另一个项目。

图19

该项目作为一个条目出现在排行榜上。

图20

第四节

总结

在这张参考卡中,我们完成了一个Java应用的创建和部署,后端使用Quarkus,前端使用React,无服务器数据库使用CockroachDB,ORM使用Panache,并使用Heroku来部署整个包。正如你所看到的,我们迅速将CockroachDB连接到Quarkus后端,但我们也可以将其作为Docker容器轻松部署到Heroku。我们还演示了使用Panache自动生成REST CRUD资源是多么容易。

所有这些工具都加速了无服务器应用程序的开发。通过消除应用开发过程中以服务器为中心的摩擦,无服务器开发使开发人员能够将更多的时间用于创新和功能开发,这将最终带来更好的终端用户体验。

喜欢这张参考卡吗?阅读更多来自DZone的文章

DZone文章

[

免费的DZone参考卡

](dzone.com/%7B%7B::rel…)