实战:从零开始搭建弹性应用

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: 作者:轶俗

一、背景介绍

(一)课程预览

1.png

Ø  What

基于Spring boot 框架 + Cassandra数据库,实现一个支持海量用户 的用户管理系统。

Ø  Why

Spring Boot大幅简化了应用搭建和开发的成本,Cassandra作为开源分布式数据库,既具备NoSQL数据库高性能,高可用,海量无限扩展的特点,又具备类似关系型数据库的数据模型,非常适合开发在线应用。

Ø  Who

Web开发入门者,希望深入了解Cassandra设计和使用的用户。

Ø  How

本文将从设计开始,手把手教用户实现一个用户管理系统

 

(二)Spring Data for Cassandra简介

1.Cassandra

- 去中心化,海量数据扩展能力;

- Zero Down Time

- 支持二级索引,物化视图,集合等实用功能;

- AppleNetflix360,华为等大公司广泛采用。

 

2.Spring Data

- 强大的存储库和灵活的抽象映射;

- 便于与Spring MVC controller 集成;

- 支持MySQLRedisRedisESCassandra等数据库。

 

3.Spring Data for Cassandra

- 降低CQL语言的学习成本,提升开发速度;

- 支持同步,反应式和异步等多种模式;

- 支持用户自定义复杂查询;

- 一套代码支持MySQL冷热分离,ES加速查询,Redis缓存等多种玩法。

 

(三)准备工作

准备工作主要分为以下三个步骤:

1.  购买Cassandra集群

1)购买Cassandra云服务

2)用户密码:云Cassandra控制台-> 集群详情->账号管理页面

3)链接URL:在数据库连接页面

3.png

2.  配置集群

1)  Cassandra控制台 -> 集群详情-> 数据库连接页面开通公网链接

2)  Cassandra控制台-> 集群详情-> 数据安全页面配置本机IP到白名单

 

3. 配置开发环境

1)下载并安装Idea开发环境

2)Spring模版生成器中生成项目模版

地址:https://start.spring.io/

3)将生成好的项目导入Idea

当完成上述步骤后,用户可以获得一个工程,如下所示:

6.png

这个工程是空的,里面只有一个Main函数可以执行,其他功能需要后续操作进行添加。

 

二、系统设计

(一)需求分析

需求分析主要分为三部分:数据需求、功能需求和其他需求。

 

1.数据需求

3.png

由于要做的是用户管理系统,用户的数据存储在Cassandra数据库中。用户数据可分为以下几个属性:用户ID、用户名、密码与用户年龄,后续可根据需求扩展更多用户信息,例如email,电话号码,住址等。

 

2.功能需求

7.png

功能一般分为增删改查4个部分。

增指的是在系统中增加一个新的用户,删指的是把用户信息删除,改指的是修改用户信息,查则较为复杂。查询可以包含很多场景,例如基于用户ID查询,基于用户年龄查询,或者要展示全部用户的信息。

 

3.其他需求

除了上述基本功能需求外,还需要注意以下四点:

1)高并发高性能

用户可能会频繁更新同一条数据,或者系统需要支撑100万个用户同时注册的场景,或者当有1亿个用户的时候,能不能快速展示全部用户,以上都属于高并发高性能场景。

2)可扩展性

系统功能在设计初期,可能有一些地方没有考虑到,例如初期没有设计通过电子邮箱地址搜索用户的功能,后续有需求需要添加这个功能,因此对可扩展性有一定的要求。

3)开发敏捷

系统最开始的功能可能开发起来并不会特别复杂,但随着系统的累加,功能会越来越复杂,因此需要注意开发敏捷性。

4)美观

该系统作为外部服务,会存在与用户交互的界面,因此希望这个界面对用户足够友好。

 

(二)Schema设计

需求完成后,我们接下来需要做的事情是设计一个Schema

这里需要注意,一定要先完成Schema的设然后再去实现功能,否则可能会导致系统性能会出现一些瓶颈。

9.png10.png

分析刚才的数据,由于ID字段是唯一的,因此可以把ID字段放在主键的位置。

主键有几个要求,首先要符合用户查询常见维度,例如上方提到的用户查询,有可能通过用户ID、年龄等信息进行查询。

ID作为主键而不是年龄的原因在于,一方面是年龄的区分度不够,很多用户拥有同样的年龄,如果以年龄做主键的话,可能会导致相同年龄的数据很多,必然要年龄后面再结合一个其他字段去保证主键的唯一。

其次,年龄作为主键可能会存在热点问题,比如所有的用户都是20~25岁,那么数据都会集中在分片,导致分片非常不均匀。

那么,把ID放在主键是不是就可以解决这些问题了呢?

这要看ID本身是否足够打散,如果是随机生成一些ID,则数据本身非常均匀。如果ID是自增的,这对于Cassandra来说并不是一个特别好的选择。对于CassandraID,我们希望尽可能去打散。当然,如果说ID把它放在Partition Key的话,因为它本身是有一些哈希可以去做打散的,因此也是可行的。

但是如果把ID放在Partition Key的话,Partition Key本身是不做排序,因此想查询ID5~100范围内的所有用户,这个查询无法实现。由于这次的系统设计较为简易,没有排序的要求,因此设计当中没有包含这项功能。

除此之外,有一个基于age字段做查询,age字段不在主键中出现。如果现在不对它建一个二级索引,它本身会转化成一个过滤逻辑,类似于全表扫描,如果数据量较小则没有问题。由于设计的目标是一个较大的用户管理系统,数据存储可能是几千万条甚至几亿条,在这些数据当中过滤出来年龄符合一定要求的存在一定难度,因此建一个二级索引加速查询。

创建二级索引的DDL如下所示:

15.png

(三)CQL设计

CQL设计遵循增删改查原则,实现方式如下。

1.

insert into test_keyspace.user(id, age, username, password) values(20, 18,'apple','banana');

2.

可以根据具体id进行删除,如:

delete from test_keyspace.user where id=20;

3.

更改分为两个部分,第一部分是更改的字段,第二部分是更改的数据,如要把id2的用户年龄改为20,则实现语句如下:

update test_keyspace.user set age=20 where id=2;

 

4.

查询分为多个方式,如果查询所有数据,则:

select * from test_keyspace.user ;

如果根据ID查询,例如id2的用户:

select * from test_keyspace.user where id=2 ;

如果根据年龄查询,例如年龄为2的用户:

select * from test_keyspace.user where age=2 ;

如果数据量少,不需要二级索引,通过年龄进行过滤查询:

select * from test_keyspace.user where age=2 allow filtering ;

n  此处必须加上allow filtering属性,否则Cassandra可能会拒绝查询。

 

 

三、编码实战

(一)代码框架

13.png

Ø  框架主要由以下几个部分构成:

1)UserController:控制层,负责与前段交互,页面跳转

2)UserService:业务层,负责处理业务逻辑

3)User RepoDAO层,负责访问数据库获取数据

4)CassandraConfig:存储Cassandra集群的访问配置

5)Resource:前端页面位置

整个代码按照MVC的设计分成数个模块。前端模块会提供三个网页,一个是list.html,用来展示User;第二个是userAdd.html,增加一个user;最后一个是userEdit.html,表示更新一个user

所有的html会把请求发到控制层和前端做交互,包括获取数据发到前端做展示,跳转到某个页面,这些都是在控制层进行。

控制层下面是业务层,传统的业务层更多的是处理一些业务的请求。我们这次的系统相对简单,业务层主要承担的作用是把DAO层的数据返回给上面的控制层。同时,业务层也会做一些简单的处理,比如统计一些用户的数目,然后将这些信息发给控制层。

最下面是DAO层,可以跟Cassandra做一一映射,负责Cassandra数据库的访问和链接。

 

(二)增删改查

1.Cassandra访问配置

15.png

在访问Cassandra之前,首先要进行访问配置。CassandraConfig本身就是在Spring Data框架里,需要继承AbstractCassandraConfiguration去定义需要的信息。

这里面包括了hostList,即数据库的连接串,这些信息可以在Cassandra管理页面找到。

第二个是keyspaceName,即访问的keyspace的具体名字。

第三个就是访问的用户名和密码,做权限的验证。

最后一个是datacenter,它其实也可以在云控制台里面去找到。在云控制台上它叫数据中心ID,不叫数据中心名称,通常情况是一个CN开头的字符串。

值得一提的是底下会有一个cassandraSession实现,它发送用户名和密码帮助Cassandra连接。

 

2.DAO

16.png

Ø  定义User对象,并指定id对应user表的PrimaryKey

完成配置后开始定义数据。刚才存的是User,这个类对应到Cassandra当中是Table表,它有4个字段,分别是IDUserNamePasswordAge。这里面有一个@PrimaryKey的定义,作用是告知Cassandra框架,ID字段是一个PrimaryKey,它是一个BIGINT。除此之外,这个实体实现了一些简单的GetSet的方法。

17.png

Ø  DAO层只需要继承CassandraRepository即可实现基本的增删改查,对于带条件的增删改查通过@Query的方式支持。

如何把实体对象真正的去与Cassandra进行读取?对于DAO层,Spring Data也做了很多事情。

如上图所示,CassandraRepository实现了很多基本的Cassandra访问,比如findAll是获取一张表里所有的数据,findAllById是可以通过ID获取一个数据,insert是插入一条数据。有了这些之后,可以实现基本的增删改操作。

如果想实现的查询比较复杂,例如基于年龄做查询,可以做一个新的interface,让userRepository继承CassandraRepository,在里面定义一种新的查询叫findByAgeSpring Data支持@Query关键词,它定义了要访问的数据。

 

3.Service

18.png

Ø  通过AutoWired标记链接DAU层;

Ø  本例子中业务逻辑比较简单,并未包括复杂的处理,实际开发过程中Service中可以处理复杂业务逻辑。

 

这里有几个需要关注的点:

第一个是类本身为@Service关键词进行标记。第二个是AutoWired属性,可以将UserRepositoryService层链接。第三个是实现了getUserNum,可以去userRepository拿到所有的数据,然后调size

 

4.Controller

19.png

Ø  @RequestMapping来映射请求,也就是通过它来指定控制器 可以处理哪些URL请求, 函数返回值标记跳转的页面地址;

Ø  返回值通过model.addAttribute返回前端。

 

(三)前端页面

19.png

前端页面的实现代码可在GitHub上查看。

左下角的add按键可以添加新用户,后右上角的EditDelete,可以对用户进行修改与删除。下方的搜索用户功能,可以根据年龄搜索用户。

 

 

四、总结

(一)功能演示

1.前端页面

20.png

2.添加用户

21.png

3.修改用户

22.png

4.按年龄搜索用户

23.png

(二)演示总结

通过上述讲解与演示,可以总结出设计系统主要有以下步骤组成:

1. 明确需求

-  需要存储什么数据

-  需要什么查询语句

2. 设计表结构

-  主键设计

-  二级索引

3. MVC实现

-  基于Model实现控制器

-  实现前端展示

n  进阶思考:

1)系统需要处理高并发,如这是一个用户点击统计,有一列是点击次数,如何能统计出用户点击的精确次数?

2)如果该用户系统需要支持100w tps/qps每秒,应该如何继续迭代?

234.png

(三)更多高级功能 - Serverless Cassandra

25.png

阿里云推出了一个新的服务叫Serverless Cassandra,核心是解决用户的资源管理成本和稳定性问题。

传统模式存在几个问题:

第一,可能用户的服务本身体量很小,如果购买数据库服务的话,起步门槛较高,成本对于用户来说不太友好。

第二,如果在使用Cassandra的过程中,用户的网站做大了,此时传统数据库需要不停地运维和规划,需要通过人为触发来扩展数据库。

第三,传统资源管理的方式需要提前规划资源,可能造成较大的资源浪费。例如用户的服务在晚上请求量较低,但在配置时需要按照高请求量场景进行配置,成本较高。

26.png

Serverless Cassandra无需任何数据库管理,实例运行于庞大的资源池 ,按使用量计费,如用电一般,随取随用,适用于不频发的、间歇性的或不可预测的工作负载。

Ø  Serverless Cassandra适用场景

1)变化或不可预测的工作负载

2)定时处理任务的场景

3)新上线应用

4)完全免运维的用户

 

Ø  Serverless Cassandra三大特性

1)简单易用

全托管,无需数据库管理;

开源标准接口,应用0 改造;

丰富生态和周边工具配套

2)经济高效

超低门槛

存储计算独立计费

按使用量计费

多存储/ 可用性级别

3)按需弹性

存储计算独立伸缩

无需容量规划,自动伸缩

相关实践学习
【文生图】一键部署Stable Diffusion基于函数计算
本实验教你如何在函数计算FC上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。函数计算提供一定的免费额度供用户使用。本实验答疑钉钉群:29290019867
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
目录
相关文章
|
C++
BaGet服务之基础搭建(上)
BaGet服务之基础搭建
299 0
|
3月前
|
缓存 监控 前端开发
从零到一:构建高性能SPA的探索与实践
作为一名高级前端工程师,我曾负责构建高性能SPA,面临首屏加载、路由切换卡顿、内存泄漏和数据加载策略等挑战。通过代码拆分、懒加载、服务端渲染、路由预加载、Keep-alive、严格管理组件生命周期、内存泄漏检测工具以及分页加载和数据缓存策略,成功优化性能,降低首屏加载时间,改善路由切换体验,控制内存泄漏,并提升数据加载效率。持续优化是关键,未来将侧重性能监控自动化和新技术探索。分享这些经验希望能激发更多同行的思考与创新。
58 1
|
3月前
|
缓存 负载均衡 监控
从零开始搭建一个高可用的后端架构
【2月更文挑战第6天】本文将介绍如何从零开始搭建一个高可用的后端架构,包括架构设计、技术选型、部署和监控等方面。通过对各种技术的分析和实践,帮助读者深入理解高可用架构的实现和优化。
|
11月前
|
运维 监控 前端开发
从零开始搭建弹性应用
从零开始搭建弹性应用
|
存储 数据库 C++
BaGet服务之基础搭建(下)
BaGet服务之基础搭建(下)
436 0
|
Kubernetes Docker Perl
【k8s 系列】k8s 学习八,在 K8S 中部署一个应用 下
接着上一篇继续部署应用到 K8S中 之前简单部署的简单集群,三个工作节点是运行在 docker 和 kubelet 的,还有一个是控制节点
102 0
|
Kubernetes 负载均衡 程序员
【k8s 系列】k8s 学习七,在 K8S 中部署一个应用 上
本身在 K8S 中部署一个应用是需要写 yaml 文件的,我们这次简单部署,通过拉取网络上的镜像来部署应用,会用图解的方式来分享一下,过程中都发生了什么
203 0
|
存储 弹性计算 运维
《企业运维之弹性计算原理与实践》——第四章 ECS 进阶概念-安全——第四章(下):ECS 安全操作演示(1)
《企业运维之弹性计算原理与实践》——第四章 ECS 进阶概念-安全——第四章(下):ECS 安全操作演示(1)
72 0
|
弹性计算 运维 监控
《企业运维之弹性计算原理与实践》——第四章 ECS 进阶概念-安全——第四章(下):ECS 安全操作演示(4)
《企业运维之弹性计算原理与实践》——第四章 ECS 进阶概念-安全——第四章(下):ECS 安全操作演示(4)
77 0
|
弹性计算 运维 安全
《企业运维之弹性计算原理与实践》——第四章 ECS 进阶概念-安全——第四章(下):ECS 安全操作演示(3)
《企业运维之弹性计算原理与实践》——第四章 ECS 进阶概念-安全——第四章(下):ECS 安全操作演示(3)
90 0