API 接口设计

news/2024/5/5 18:30:43/文章来源:https://blog.csdn.net/Noah_ZX/article/details/130041584

1、场景描述

  比如说我们要做一款 APP,需要通过 api 接口给 app 提供数据。假设我们是做商城,比如我们卖书的。我们可以想象下这个 APP 大概有哪些内容:

  1)首页:banner 区域(可以是一些热门书籍的图片做推广)、本周热卖书籍区域、本月好评书籍区域、活动打折的书籍区域。。。

  2)排行榜:比如第一季度热销榜、新书版。。。

  3)书单:管理后台运营添加的书单,比如《程序员从入门到放弃》系列书单。。。

  4)用户相关的:比如用户个人信息设置、订单管理、消息管理、收藏的书籍。。。

  数据是保存在数据库中,考虑到高并发数据库的瓶颈,采用 DB + 缓存的服务器架构。

2、重要接口汇总

  看似简单的一个 app,需要调用的 api 接口是非常多的,总结下大概有这几类接口:

1)列表接口:比如书单里面的书籍列表、排行榜的书籍列表;

2)详情接口:书籍的详细信息;

3)评论接口:书籍评论(这里可能要求购买了的才能评论)、星标;

4)点赞接口:给书籍点赞、给书单点赞;

5)收藏接口:收藏书籍、收藏书单;

6)“相关” 接口:比如书籍《php 从入门到放弃》相关的有哪些书籍;

7)关注接口:关注某本书或者书籍作者,一旦某本书有打折或者作者有新书,会推消息等等。或者是用户间互相关注;

8)发布接口:比如用户可以发布书单。A 用户发布了书单,B 用户可以关注 A 用户,A 用户再发布新书单,会给 B 用户推消息等等;

9)搜索接口:查询书籍、查询书单、查询用户等等

3、后台管理系统

1)书籍信息的来源:爬虫抓取的数据、运营人员在管理后台添加;

2)书籍的价格、库存等信息,是可以在后台设置;

3)书籍的分类、书籍的标签,像爬虫如果抓取不到的,运营可以手动设置;

4)书籍的排序:在管理后台设置,用于在 app 上展示的先后顺序;

5)书单管理:运营可以添加、可以设置展示 / 隐藏;用户提交的书单,在后台进行审核;

6)用户的评论:在后台审核;

备注:管理系统还有很多功能,简单先写这几个。

4、api 接口设计

接口设计要遵循的一个想法:可以先从缓存读取,读取不到,再去数据库读取,然后写回缓存。

1)banner 数据: key-value 类型(string 类型)

redis key 名: index:banners   这个 key 是首页上面的 banner 可以设置一个缓存时间:1 小时

里面保存的数据是从数据库获取出来的 banner 数据,json 之后保存的字符串。

2)实时性问题

比如数据是在管理设置的,比如 banner 数据添加了一条,或者某一个 banner 数据被删除了或者改为不展示了,但是缓存里面还没变化,怎么处理?

【方案一】不做处理,等待缓存自己过期,然后再有请求获取的就是新的数据。缓存要有个过期时间,这个要看业务需要设置相应的缓存过期时间,比如 5 分钟。

【方案二】管理后台对 banner 有添加删除修改操作时,修改成功的同时把缓存中的数据也更新。这个方案不太赞成,因为这样子数据就有 2 个地方维护了,

一个是 api 接口访问的时候,如果缓存过期会回源写缓存,一个是管理后台;

【方案三】解决方案二的缺点,就是管理后台有数据增加删除修改的时候,把对应的缓存删掉,这样子 api 接口从缓存读取不到 key 就会重新生成缓存。这样也是比较实时的。 

3)详情数据

详情信息可以放在缓存里面,key-value 类型,设置一个过期时间

redis key 名: book:detail:{book_id} 

4)列表数据:key-value 类型

【方案一】把每一页的数据缓存起来,这样 api 接口来获取的时候,直接把一页的数据从缓存取出来然后返回。

redis key 名:index:book_list:{page}    缓存时间根据实际业务设置

假设每一页 20 条数据,这里保存的就是 20 条数据的 json 后的字符串,key 名里面有页码,每一页的数据用不同的 key 名缓存起来。

这个方案有个问题,比如管理后台删除一条数据,刚好缓存重新生成了,那么第一页的 20 条数据肯定是最新的,但是第二页如果缓存没有重新生成的,

那么新的第一页和旧的第二页会有一条数据重复。当然,如果新增数据那么第一页的缓存和第二页的缓存数据中间有一条数据遗漏了。。。

【方案二】把 id 放入有序集合,每次获取列表,从集合中获取出 20 个 id,然后去缓存中获取详情数据,然后返回。

管理后台如果有新增删除,那么就在集合里面新增或删除。 这里相比方案一,就是每次要去缓存获取 20 条详情信息,虽然缓存中获取很快但是也有一定的开销,但是数据最实时。

还有一个问题,感觉就是有点耦合,就是万一集合失效,那么要重建集合,假如数据很多,比如有几十万几百万个 id,那么要去数据库获取,然后写入缓存,有这种隐患。

【方案三】不用缓存,采用像 spinx、es 这些搜索引擎。通常有些业务需要很多排序规则,比如 sort 字段、时间字段、销量字段等等等,这个时候如果硬是要用方案二,

就必须是把排好序的数据保存如有序集合,比如 id=1,序号 = 1;id=15,序号 = 2;id=8,序号 = 3,每次有新增、删除,就要重新生成集合,很不好维护。

使用搜索系统来辅助,可以应该解决方案一和方案二的问题。当然了,看业务,如果不要紧的,方案一即可。像新浪博客、今日头条,之前也看到他们有些分页数据有重复的。

5)点赞接口

根据不同的业务要求,有些业务是只有点赞,没有取消点赞,我们就讨论这个有取消点赞的。

首先,假设我们有个业务是对书籍点赞,点赞之后可以取消点赞。比如说 APP 首页的列表里面需要点赞数,而且要实时,怎么处理?

我们肯定有个数据表来存储点赞信息,比如 book_like 表,里面记录了用户对书籍的点赞信息。

鉴于点赞数如果每次用户接口请求都去数据库请求,会给数据库增加压力,我们使用 redis 来减压。这里使用 hash 类型,下面会讲为何。

redis key 名:  book:like:{hash_id}  内容: field =》 value

这里的 hash_id 是 book_id / 1000 的结果

field 的值是 book_id % 1000 的结果

value 的值是点赞数

为何这种设计:hash 相比 string 类型有个优势,在满足 2 个条件的时候会进行压缩,就是内存的占用会小很多。

这两个条件是 hash 里面的 field 的数量小于指定数量(貌似默认是 512 还是 1024),另外一个条件是 value 值的大小要小于 64 字节(这个也是可以调整的,配置信息里面改)。

举个例子:

book_id = 100, 那么 hash_id 就是 0,field 是 100,值是点赞数

book_id = 1001, 那么 hash_id 就是 1,field 是 1,值是点赞数

列表接口里面有点赞数,可以从 hash 中获取

多次 redis 的 get 请求(get、hget 等),可以用管道(pipeline)来一次性获取,也会提高速度

点赞的时候,数据肯定是要写入数据库的,有 2 种方案处理:

【方案一】

书籍表里面比如有个点赞数字段,每次点赞 / 取消点赞,就是往里面加 1 减 1。

点赞表就是往里面增加或删除数据(可以是软删除)。

像 php 的 laravel 的 eloquent 模型是支持直接给字段 +-1 这样,不需要先取出数据再加。

【方案二】

先写入缓存,然后定期把缓存的数据取出来然后写入数据库。这个方案的话有点耦合了,比如需要定时脚本去写回数据库。

【方案三】

不使用缓存,数据直接更新回 book 表,或者 book 表不需要这个字段,需要点赞数的时候去 book_like 表计算,如果是有搜索引擎系统,那么应该不成问题。

6)相关接口

比如根据分类关联书籍。《php 从入门到放弃》和《php 从入门到奔溃》关联。

数据库里面可以根据分类 id 查找。简单的业务可以通过集合存储分类 id 下有哪些书籍。

如果复杂的业务,比如书籍有多个分类,比如分类 id=1  , 分类名称:php,分类 id=2 ,分类名称:程序开发,假设这 2 个分类是同级的,

那么可能有一些书是同时属于这 2 个分类的。

又或者有些业务下,是根据标签来关联,一个书籍可以有多个标签,标签和书籍是多对多关系。

此时又要来一句搜索系统可以处理。。。缓存也不是不能处理,感觉有些场景缓存处理起来很费劲。

以上只是一些很肤浅的看法,肯定有更好的处理方案,待研究补充上。

5、api 接口设计总结

  考虑到高并发时数据库的瓶颈,所以需要把请求的结果缓存起来。这里的策略是:

1)从缓存中获取数据,缓存中有数据则直接返回,或者做简单处理然后返回;

2)缓存没有数据,则从 DB 中查找数据,然后写回缓存;这种情况叫做 “回源”。

3)缓存的 key 是需要设置过期时间的,避免数据一直占用内存;

4)过期时间的设计,最好是打乱,避免同一时间有大量的 key 过期导致请求集中去 DB 请求导致雪崩;

5)根据业务需求,“回源” 的时候考虑申请到缓存锁的请求去数据库获取数据并更新缓存,其他请求则 sleep 一段时间(比如 5 毫秒 10 毫秒)然后再去缓存请求,如果请求还是没数据,可以继续等待或者直接返回空数据。

6)没有必要缓存起来的字段,不要缓存;

7)APP 不需要用到的字段没有必要返回给 APP,比如评论的审核时间、审核者,返回给 APP 是没用的,因为这些数据不需要展示出来,不会被用到;

8)减少 api 请求的次数,比如多次请求,要看下能否合并,比如首页,有好几个区域,每个区域都有几条数据。当然多次请求一样可以实现,但是请求次数少,则服务器可以接受更多客户端的请求。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_285732.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第十四届蓝桥杯大赛软件赛省赛 C/C++ 大学 A 组题解+个人总结

提示:此题解为本人自己解决,如有差错请大家多多指正。 文章目录题解总结一、幸运数1.试题2.解法3.代码二、[有奖问答](https://blog.csdn.net/A2105153335/article/details/130038980?spm1001.2014.3001.5501)三、[平方差](https://blog.csdn.net/A2105…

js flyout 2: VScroll

目录版权描述测试页面showFlyout问题1 - scroll 实现可能不准?问题2 - 容器内容重排可导致浮层错位关于重排小结附录 - 完整代码版权 本文为原创, 遵循 CC 4.0 BY-SA 版权协议, 转载需注明出处: https://blog.csdn.net/big_cheng/article/details/130101031. 文中代码属于 pu…

数据结构与算法01 稀疏数组

稀疏数组问题 当一个二维数组中大部分数据都是0,对这个数组直接进行存储会很浪费空间,因此利用稀疏数组进行压缩,稀疏数组第一行的第一个元素是原二维数组行数。,第一行的第二个元素是原二维数组的列数,如图为11行11列…

6.S081——虚拟内存部分——xv6源码完全解析系列(4)

0.briefly speaking 点击跳转到上一篇博客 好,现在进入下一个话题,就是物理内存分配器(kernel/kalloc.c)。在简单介绍完内核态的物理内存分配器之后,之后简单带过一下两个头文件riscv.h和memorylayout.h这两个头文件,因为它们都…

2.5d风格的游戏模式如何制作

文章目录一、 介绍二、 绘制瓦片地图三、 添加场景物体,添加碰撞器四、 创建玩家五、 创建玩家动画六、 玩家脚本七、 2d转换成2.5d八、 “Q”键向左转动视角、“E”键向右转动视角九、 下载工程文件一、 介绍 制作一个类似饥荒风格的2.5d游戏模板。 2.5D游戏是指以…

表id自增的方法

数据库主键id自增的方法,列举了几种如下 一、数据库自增(部分数据库支持) 创建表的时候设置id自增即可,或者后期修改表id自增 # mysql 语法 create table your_table_name(id bigint(20) not null auto_increment primary key …

Markdown 语法大全

Markdown是一种轻量级标记语言,常用于撰写博客、文档、论文等。它可以让你使用易读易写的纯文本格式来编写文档,然后通过转换成有效的HTML文档进行发布。以下是Markdown常用的语法: 这里写目录标题标题列表引用一级引用嵌套引用粗体和斜体删除…

Java集合——Set接口学习总结

一、HashSet实现类 1.常用方法 增加&#xff1a;add(E e)删除&#xff1a;remove(Object o)、clear()修改&#xff1a;查看&#xff1a;iterator()判断&#xff1a;contains(Object o)、isEmpty()常用遍历方式&#xff1a;Set<String> set new HashSet<String>()…

Spark 对hadoopnamenode-log文件进行数据清洗并存入mysql数据库

一.查找需要清洗的文件 1.1查看hadoopnamenode-log文件位置 1.2 开启Hadoop集群和Hive元数据、Hive远程连接 具体如何开启可以看我之前的文章&#xff1a;(10条消息) SparkSQL-liunx系统Spark连接Hive_难以言喻wyy的博客-CSDN博客 1.3 将这个文件传入到hdfs中&#xff1a; hd…

windows系统管理_windows server 2016 用户管理

用户账户的概述 **计算机用户账户&#xff1a;**由将用户定义到某一系统的所有信息组成的记录,账户为用户或计算机提供安 全凭证&#xff0c;包括用户名和用户登陆所需要的密码&#xff0c;以及用户使用以便用户和计算机能够登录到网络并 访问域资源的权利和权限。不同的身份拥…

【Obsidian】基础使用手册(包括如何将Obsidian页面设置为中文)

&#x1f497; 未来的游戏开发程序媛&#xff0c;现在的努力学习菜鸡 &#x1f4a6;本专栏是我关于工具类软件的笔记 &#x1f236;本篇是Obsidian的基础使用 Obsidian的基础使用将页面设置为中文常用的默认快捷键常用的格式标题代码块表格字体样式列表任务列表官方下载地址&am…

【音视频第11天】GCC论文阅读(2)

A Google Congestion Control Algorithm for Real-Time Communication draft-alvestrand-rmcat-congestion-03论文理解 看中文的GCC算法一脸懵。看一看英文版的&#xff0c;找一找感觉。 目录Abstract1. Introduction1.1 Mathematical notation conventions2. System model3.Fe…

获取淘宝商品分类详情API,抓取淘宝全品类目API接口分享(代码展示、参数说明)

商品分类技巧 淘宝店铺分类怎么设置&#xff1f;我们登录卖家账号的时候&#xff0c;我们看到自己的商品&#xff0c;会想要给商品进行分类&#xff0c;一个好的分类可以帮助提高商品的曝光率。那么在给商品分类前&#xff0c;如果您毫无头绪&#xff0c;以下几点可以给您带来…

车载网络 - Autosar网络管理 - 网络管理简介

一、什么是CAN网络管理及它的作用 现在的车辆是由大量的ECU节点组成的&#xff0c;为了能使各ECU能够正确并及时地进行CAN通信&#xff0c;需要有一套机制来统一协调总线上各节点的休眠唤醒&#xff0c;这套机制就是CAN网络管理&#xff08;NM&#xff09;。 网络管理的目的是保…

【算法题解】24. 模拟机器人行走

这是一道 中等难度 的题 https://leetcode.cn/problems/walking-robot-simulation/description/ 题目 机器人在一个无限大小的 XY 网格平面上行走&#xff0c;从点 (0, 0) 处开始出发&#xff0c;面向北方。该机器人可以接收以下三种类型的命令 commands &#xff1a; -2 &am…

WPF mvvm框架Stylet使用教程-基础用法

Stylet框架基础用法 安装Nuget包 在“管理Nuget程序包”中搜索Stylet&#xff0c;查看Stylet包支持的net版本&#xff0c;然后选择第二个Stylet.Start包进行安装&#xff0c;该包会自动安装stylet并且生成基本的配置 注意事项&#xff1a;安装时要把需要安装的程序设为启动项…

PyCharm2021安装教程

PyCharm是一种Python IDE&#xff0c;带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具&#xff0c;比如调试、语法高亮、Project管理、代码跳转、智能提示、自动完成、单元测试、版本控制。此外&#xff0c;该IDE提供了一些高级功能&#xff0c;以用于支持Djang…

IntersectionObserver与无限滚动加载

学习链接 IntersectionObserver MDN Api IntersectionObserver API详解 Intersection observer 的概念和用法 过去&#xff0c;要检测一个元素是否可见或者两个元素是否相交并不容易&#xff0c;比如实现图片懒加载、内容无限滚动等功能时&#xff0c;都需要通过​getBound…

[Date structure]时间/空间复杂度

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;数据结构。数据结构专栏主要是在讲解原理的基础上拿Java实现&#xff0c;有时候有C/C代码。 ⭐如果觉得文章写的…

linux文件类型和根目录结构

目录 一、Linux文件类型 二、Linux系统的目录结构 1. FHS 2. 路径以及工作目录 &#xff08;1&#xff09;路径 &#xff08;2&#xff09;工作目录 一、Linux文件类型 使用ls -l命令查看到的第一个字符文件类型说明-普通文件类似于Windows的记事本d目录文件类似于Windo…