什么是架构及架构师
写在前面2024年笔者正式步入到架构设计的领域,因此有必要记录自己在架构设计方面学习的点滴。由于每个业务系统都要求从业务架构的视角进行代码开发和迭代,因此架构师属性不仅仅是作为架构师所必备的技能,更是作为每个开发者应当具备的属性,这种架构师可称为纵向架构师,而目标在于提高整个团队水平,确定多业务边界的,笔者称之为横向架构师。
【纵向架构师】主要考虑业务和系统,做问题和结果的定义,做系统、模块、代码设计;
【横向架构师】解决跨域问题,确定跨团队边界,定义规范、统一语言。定义纵向架构能力基础/标准的成长路径和方法论,让人人都成为架构师。即它的核心过程是探讨如何完成架构设计,如何培养和拥有架构思维。
什么是架构师定义关于架构师的定义,wiki百科是这样定义的:
软件架构师定义和设计软件的模块化,模块之间的交互,用户界面风格,对外接口方法,创新的设计特性,以及高层事物的对象操作、逻辑和流程。软件架构师与客户商谈概念上的事情,与经理商谈广泛的设计问题,与软件工程师商谈创新的结构特性,与程序员商谈实现技巧,外观和风格。
笔者认为,架构师主要有如下三个职责:
(1)跟需求方,提炼关于项目的概念 ...
巧用分页列表缓存,快速响应用户请求
写在前面最近在写数据报表逻辑,里面大部分场景都是统计数据,对数据时效性要求不高,不过要求数据能立即响应用户。于是尝试借助缓存来加快响应用户的时间,主要用到了分页列表缓存。
直接缓存分页列表说明最简单,也是最能想到的方法就是直接缓存分页列表。举个例子,如下所示,直接将每页的数据以列表形式进行缓存:
对应的伪代码如下所示:
123456789public List<Product> getPageList(String param, int pageNum, int pageSize) { String key = "productPageList:pageNum:" + pageNum+ "pageSize:" + pageSize+ "param:" + param ; List<Product> productList = cacheUtil.get(key); if(productList != null)return productList; productL ...
基于请求参数校验的接口幂等性实现方案
写在前面前面笔者使用的都是基于token令牌校验这一方式实现接口幂等,这种方式其实比较复杂,今天来介绍另一种比较简单的方式—基于请求参数的校验,这种方式在高并发环境下优势更明显。由于请求只有一次,所以不需要从服务端获取令牌。
原理介绍基于请求参数校验这一方式原理很简单,如果在某一个时间间隔内,同一个接口接收到的请求参数一样,则说明前后请求是重复的,服务端则拒绝处理后续请求。注意由于前后端通过JOSN格式传递数据,且需要多次重复读取JSON数据,所以前面介绍的文章还是有很大的帮助。
实战第一步,新建一个名为repeat-submit的SpringBoot项目,然后在POM文件中引入redis、web和aop依赖:
123456789101112<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId></dependency><depe ...
Redis各种数据类型巧用
写在前面最近参与了一个社交系统的前期需求评审会议,里面涉及到各种社交应用场景,使用Redis无疑是最合适不过的了。通常会保存这样的信息:一个key关联一个数据集合,同时要对集合中的数据进行各种操作,诸如统计、排序等。
那么本篇笔者将结合工作实际,列举六种典型使用Redis的业务场景,如下所示:(1)判断用户登录状态;(2)统计用户连续签到情况;(3)统计每天新增和第二天用户留存数;(4)统计网站访客量(Unique Visitor,UV);(5)最新评论列表;(6)积分排行榜。
一般来说,我们面临的用户数量和访问量都是巨大的,如百万、千万级别用户数量,或者千万甚至亿级别的访问量,因此必须选择能够高效统计大量数据的集合类型。不过在此之前,首先需要了解常用的统计模式,并使用合理的数据类型来解决实际问题。
这里我们一般会使用如下四种统计类型:二值状态统计、基数统计、排序统计和聚合统计。
二值状态统计二值状态统计概念二值状态统计,即集合中的元素只有0和1这两种状态,统计对应状态出现的次数。
举个例子,用户在进行打卡签到的时候,只有签到(1)或未签到(0)这两种;判断用户是否登录,也只有已登录( ...
聊一聊Redis中的布隆过滤器
写在前面写在前面本篇来聊一聊Redis中的布隆过滤器,主要包括布隆过滤器原理、Redis集成布隆过滤器以及一个demo实战。
业务场景在实际开发过程中遇到过这种情况,用户在使用APP阅读文章时,如何做到每次推荐给该用户的文章不重复,即需要过滤掉他已经阅读过的文章。
此时有人可能会说我们可以记录每个用户的浏览历史,然后每次在推荐的时候查询用户的浏览记录并进行过滤,进而实现文章的去重。如果开发者将用户的浏览历史存储在关系型数据库中,那么就需要频繁的对数据库进行exists判断,在并发量不高的情况下还能正常响应,但是一旦并发量上来,数据库是扛不住的。
那么又有人说,可以将这些浏览历史存在缓存中。请注意,千万不要将它们存在缓存中,这样会浪费很多内存,而且缓存适合更新频率比较低的情况,而用户的浏览历史可能每时每刻都在变化。
针对上述情况,即遇到数据量较大,又需要去重的时候,就可以考虑使用布隆过滤器。一般来说,布隆过滤器适用于如下场景:(1)解决Redis中缓存穿透问题;(2)爬虫过滤,对爬虫爬过的网站进行过滤,爬过的不再爬取;(3)内容推荐,对已经推荐过的内容进行过滤,不再推荐;(4)邮件过滤, ...
功能开关在业务中的实践
写在前面之前搞过一个报名送油卡的活动,这个活动不定期举办,因此需要考虑可配置性,起初考虑后台做个时间配置框,根据指定的时间来生效,但是后续发现这样有个弊端,即只能针对一个活动或者相同时间的多个活动生效,而实际上我们的活动有多个,权衡再三决定使用功能开关来实现。
功能开关功能开关其实是一种代码可配置性的实践,说到底就是通过控制开关的状态来实现对功能的决定控制。
功能开关的实现有很多种方式,可以使用MySQL或者Redis等数据库,出于对后续数据扩展和对存储容量的考量,此处使用Bit数组来实现。
Bit数组原理既然是数组,那么下标必然从0开始,bit只有两种取值,要么为0,要么为1:
而0和1正好对应开关的关闭和启用,即ON和OFF状态。之后开发者只需定义好每个开关所在的Bit数组的索引号和状态即可,这样后续就可以通过判断开关的状态来实现对功能的控制:
可以看到使用这种方式所占用的内存空间非常少,理论上只需占用2n位的内存,n为开关的数量。
实战演示Java中对于Bit数组可以使用BitSet来实现 ,里面有很多方法,这里我们摘几个用到的方法:
12345678public class ...
使用Jenkins+Gitlab一键打包部署SpringBoot应用
写在前面在前面我们已经学会了如何通过使用Maven插件或者Dockerfile的方式,来将SpringBoot应用构建为Docker镜像并运行。当我们的应用数量较多时,还可以使用Docker Compose的方式,但是毫无疑问上面的种种还都只是手动部署,本篇来学习如何使用Jenkins和Gitlab来实现一键打包部署SpringBoot应用。
GitLabGitLab简介GitLab是一款开源的基于Git的版本仓库管理工具,开发者可以使用它来搭建属于自己的Git仓库。
GitLab安装第一步,下载GitLab的docker镜像:
1docker pull gitlab/gitlab-ce
第二步,创建对应目录:
123mkdir -p /mydata/gitlab/configmkdir -p /mydata/gitlab/logsmkdir -p /mydata/gitlab/data
第三步,启动GitLab服务:
1234567docker run -p 10443:443 -p 1080:80 -p 1022:22 \--name gitlab \--restart alway ...
使用Docker Compose部署SpringBoot应用
写在前面在前面我们已经学会了如何通过使用Maven插件或者Dockerfile的方式,来将SpringBoot应用构建为Docker镜像并运行,但是当我们的应用数量较多时,上述两种方式似乎变得很不友好。
此时可以使用Docker Compose来解决上述问题,Docker Compose是一个用于定义和运行多个docker容器应用的工具。使用Compose允许开发者使用YAML文件来配置应用服务,之后使用一个命令,就可以部署配置的所有服务。
安装Docker Compose下载Docker Compose使用如下命令来下载Docker Compose:
1curl -L https://get.daocloud.io/docker/compose/releases/download/1.24.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
修改下载文件的权限将下载文件的权限设置为可执行:
1chmod +x /usr/local/bin/docker-compose
确认Docker C ...
使用Dockerfile为SpringBoot应用构建Docker镜像
写在前面在部署第一篇中,我们学习了如何使用通过docker-maven-plugin来构建docker镜像,遗憾的是此方式需要依赖自建的Registry镜像仓库,这在实际开发过程中还是有困难的。
鉴于此,本篇来学习另一种方式,使用Dockerfile来构建docker镜像。注意此方式不需要依赖自建的镜像仓库,只需应用的jar包和一个Dockerfile文件。
本篇在第二篇《整合Swagger-UI实现在线API文档》的基础上,使用Dockerfile为SpringBoot应用构建Docker镜像。
Dockerfile常用指令FROMFROM用于指定所需依赖的基础镜像,格式如下:
1FROM <image>:<tag>
举个例子,如某个镜像需要依赖java8的镜像:
1FROM java:8
注意FROM命令必须放在Dockerfile文件的第一行。
MAINTAINERMAINTAINER用于指定镜像维护者的名字,格式如下:
1MAINTAINER <name>
举个例子,如某个镜像的维护者为kenbings:
1MAINTAINER kenbin ...
使用Maven插件为SpringBoot应用构建Docker镜像
写在前面本篇在第二篇《整合Swagger-UI实现在线API文档》的基础上,使用Maven插件为SpringBoot应用构建Docker镜像,并上传至私有镜像仓库Docker Registry中。
Docker Registry开发者可以使用Docker提供的registry这一镜像来搭建属于自己的私有仓库,这里选择版本为2的镜像即可,先将其下载到本地:
1docker pull registry:2
这里有它的快速使用方法,其实就是一条命令:
执行下面的命令即可创建一个私有仓库:
1docker run -d -p 5000:5000 --restart=always --name registry2 registry:2
Docker开启远程API打开docker.service文件:
1vi /usr/lib/systemd/system/docker.service
将其中的如下代码:
1ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
修改为如下所示:
1Exec ...