整个系统采用b2c的管理模式,分为管理员系统和用户系统(直接商对客)
1 后端整合Swagger进行技术测试
2 后端框架使用ssmp框架
3 logback和 log4j 作为日志实现框架
4 idea开发后端
5 vscode开发前端
6 vue做前端框架
7 ES6标准的JS语言写前端
8 element-ui进行前端组件开发
9 axios数据交互(Ajax)
10 node.js部署前端的后端服务器(内置V8引擎),即前端人员不需要tomcat那一套了
利用node.js就可以部署项目了(javascripti运行环境、模拟服务端效果)
11 使用NPM包管理前端工具,相当于前端的maven
注意:这时的程序无法运行的,因为ES6的模块化无法在Node.js中执行,需要用Babel编辑成ES5后再执行。
12 babel转码器(把es6转成es5)
13 Webpack 是一个前端资源加载/打包工具(Webpack 可以将多种静态资源 js、css、less 转换成一个静态文件,减少了页面的请求,加快页面加载速度 )
14 vueAdmin-template作为前端管理员系统模板(不是框架)进行二次开发
15 前端开发流程
16 使用nginx作为反向代理服务器,提供统一的api接口
(后续我们将了Spring Cloud Gateway网关,将替代nginx网关)
运行输入cmd命令,打开命令行
切换到nginx.exe所在的目录,命令:cd /d D:\nginx-1.15.8,注意要加 /d
nginx 启动:start nginx
nginx 停止:nginx -s stop
彻底杀死多个线程:taskkill /f /t /im nginx.exe
nginx 退出:nginx -s quit
17 设计数据字典
利用EasyExcel实现Excel与数据库的读写操作
EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。
18 数据缓存(redisson分布式锁)
Spring Cache(spring自带) + Redis 数据库(在linux centos系统下后台运行)缓存数据
19 nginx 控制端口跳转(nginx作为反向代理服务器)
20 docker容器镜像文件(一次镜像,处处运行,相当于一个打包技术 .iso文件)
借助了阿里云个人版容器镜像服务
21 应用了mongdb数据库存储大量后台数据
22 Nacos(注册中心与服务调用) 是阿里巴巴推出来的一个新开源项目,这是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台 实现不同模块间的远程调用,
注册不同模块的ip和端口号(类似的还有Eureka 、zookeeper、Consul)
23 Spring Cloud Gateway
通过网关限定哪些url需要用户登录,哪些不需要用户登录
API网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:
(1)客户端会多次请求不同的微服务,增加了客户端的复杂性。
(2)存在跨域请求,在一定场景下处理相对复杂。
(3)认证复杂,每个服务都需要独立认证。
(4)难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施。
(5)某些微服务可能使用了防火墙 / 浏览器不友好的协议,直接访问会有一定的困难。
以上这些问题可以借助 API 网关解决。API 网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过API 网关这一层。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由 API 网关来做,这样既提高业务灵活性又不缺安全性
Spring cloud gateway是spring官方基于Spring 5.0、Spring Boot2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供简单、有效和统一的API路由管理方式,Spring Cloud Gateway作为Spring Cloud生态系统中的网关,目标是替代Netflix Zuul,其不仅提供统一的路由方式,并且还基于Filer链的方式提供了网关基本的功能,例如:安全、监控/埋点、限流等
24 nuxt做前端用户系统开发(服务端渲染技术NUXT),更好地SEO
服务端渲染技术(SSR),让页面渲染在服务端进行 而不是在客户端进行,从而更快的展示页面
Nuxt.js 是一个基于 Vue.js 的轻量级应用框架,可用来创建服务端渲染 (SSR) 应用,也可充当静态站点引擎生成静态站点应用,具有优雅的代码结构分层和热加载等特性。
25 使用JWT 生成 token
26 OAuth2针对一些特定问题解决方案
1)开放系统间的授权问题
你平常登录网页时,有微信,支付宝授权登录 就是这玩意~
方式一:用户密码复制
方式二:通用的开发者key
方式三:颁发令牌,设置令牌(字符串)有效时间,随时解除令牌-OAuth2方式(JWT也属于一种)
2)单点登录问题
商易通项目设置了医院、用户、数据字典等多个模块,通过OAuth2方式,你只需要在其他某个模块登录,剩余模块直接访问
百度登陆以后。百度网盘,百度文库等都不需要再登录了
27 微信登录二维码文档
28 阿里云OSS云文件存储系统,存储图片文件
29 使用RabbitMQ 极大提高系统的并发性
消息队列提供一个异步通信机制,消息的发送者不必一直等待到消息被成功处理才返回,而是立即返回。消息中间件负责处理网络通信,如果网络连接不可用,消息被暂存于队列当中,当网络畅通的时候在将消息转发给相应的应用程序或者服务,当然前提是这些服务订阅了该队列。如果在商品服务和订单服务之间使用消息中间件,既可以提高并发量,又降低服务之间的耦合度。
RabbitMQ就是这样一款消息队列。RabbitMQ是一个开源的消息代理的队列服务器,用来通过普通协议在完全不同的应用之间共享数据。
异步处理。把消息放入消息中间件中,等到需要的时候再去处理。
流量削峰。例如秒杀活动,在短时间内访问量急剧增加,使用消息队列,当消息队列满了就拒绝响应,跳转到错误页面,这样就可以使得系统不会因为超负载而崩溃。
30 使用
@EnableScheduling //开启定时任务操作,在线生成Cron表达式
31 缺少高并发,分布式事务,注意系统安全和线程并发
分布式事务
分布式系统(用户吗、医院等有自己的微服务且查询不同的数据库)
会出现机器宕机,网络异常,消息丢失,消息乱序,数据错误,不可靠的TCP,存储数据丢失等异常
1、CAP定理
CAP原则又称CAP定理,指的是在一个分布式系统中
一致性(Consistency).:
在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访
问同一份最新的数据副本)
可用性(Availability)
在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据
更新具备高可用性)
分区容错性(Partition tolerance)
大多数分布式系统都分布在多个子网络。每个子网络就叫做一个区(partition).
分区容错的意思是,区间通信可能失败。比如,一台服务器放在中国,另一台服务
器放在美国,这就是两个区,它们之间可能无法通信。
CAP原则指的是,这三个要素最多只能同时实现两点,不可能三者兼项。
分区容错性一定要有,一致性和可用性二选一
在分布式系统中实现一致性的 raft算法和paxos算法
raft算法(领导与随从:)类似redis哨兵算法(主从复制)-一个客户一个产品经理+n个打工仔
看谁的超时时间更短 election timeout
但实际中,大型互联网集群应该保证P和A舍弃C,只需要实现(弱一致)最终一致性即可
实际中遵循BASE原则
BASE是指
1 基本可用(Basically Available)
基本可用是指分布式系统在出现故障的时候,允许损失部分可用性(例如响应时间、功能上的可用性),允许损失部分可用性。需要注意的是,基本可用绝不等价于系统不可用。
响应时间上的损失:正常情况下搜索引擎需要在0.5秒之内返回给用户相应的查询结果,但由于出现故障(比如系统部分机房发生断电或断网故障),查询结果的响应时间增加到了12秒。
功能上的损失:购物网站在购物高峰(如双十一)时,为了保护系统的稳定性,部分消费者可能会被引导到一个降级页面。
2 软状态(Soft State)
软状态是指允许系统存在中间状态,而该中间状态不会影响系统整体可用性。分布式存储中一般一份数据会有多个副本,允许不同副本同步的延时就是软状态的体现。mysql replication的异步复制也是一种体现。
3 最终一致性(Eventual Consistency)
最终一致性是指系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。弱一致性和强一致性相反,最终一致性是弱一致性的一种特殊情况。
分布式事务常见解决方案
1 2PC模式 又叫XA Transactions,二阶提交方案
(阿里巴巴提供了Seata分布式事务解决方案,加注解即可)
2 TCC事务补偿性方案(阿里在用)
3 最大努力通知型方案
按规律进行通知
不保证数据一定能通知成功,但会提供可查询操作接口进行核对。这种方案主要用在于第三方系统通讯时,比如:调用微信或支付宝支付后的支付结果通知。这种方案也是结合MQ让行实现,例如:通过MQ发送http请求,设置最大通知次数。达到通知次数后即不再通知。
高并发方法论(考虑限流,熔断,降级)
SpringCloud Alibaba-Sentinel
什么是熔断
A服务调用B服务的某个功能,由于网铬不稳定问题,或者B服务卡机,导致功能时间超长。如果这样子的次数太多。我们就可以直接将B断路了(A不再请求B接口),凡是调用B的直接返回降级数据,不必等待B的超长执行。这样B的故障问题,就不会级联影响到A.
什么是降级
整个网站处于流量高峰期,服务器压力剧增,根据当前业务情况及流量,对一些服务和页面进行有策略的降级[停止服务,所有的调用直接返回降级数据]。以此缓解服务器资源的的压力,以保证核心业务的正常运行,同时也保持了客户和大部分客户的得到正确的相应。
什么是限流
对打入服务的请求流量进行控制,使服务能够承担不超过自己能力的流量压
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel以流量为切入点,
从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
32 feign调用服务注册中心的服务
Feign
Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端
Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。
Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务
Feign支持的注解和用法请参考官方文档:https://github.com/OpenFeign/feign
Feign本身不支持Spring MVC的注解,它有一套自己的注解
OpenFeign
OpenFeign是Spring Cloud 在Feign的基础上支持了Spring MVC的注解,如@RequesMapping等等。
OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,
并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
33 压力测试 jmeter
压力测试考察当前软硬件环境下系统所能承受的最大负荷并帮助找出系统瓶颈所在。压测都是为了系统在线上的处理能力和稳定性维持在一个标准范围内,做到心中有数。
使用压力测试,我们有希望找到很多种用他测试方法更难发现的错误。有两种错误类型是:内存泄漏,并发与同步。
内存泄漏:系统内存不足导致对象创建以后,无法正常释放
并发与同步:系统单线程没问题,并发量一上来,出现线程不安全等诸多问题
有效的压力测试系统将应用以下这些关键条件:重复,并发,量级,随机变化。
性能指标
响应时间指用户从客户端发起一个请求开始,到客户端接收到从服务器端返回的响应结束,整个过程所耗费的时间。
HPS(Hits Per Second):每秒点击次数,单位是次/秒。
TPs(Transaction per Second):系统每秒处理交易数,单位是笔/秒。
QPS(Query per Second):系统每秒处理查询次数,单位是次秒。
对于互联网业务中,如果某些业务有且仅有一个请求连接,那么TPS=QPS=HPS,一般情况下用TPS来衡量整个业务流程,用QPs来衡量接口查询次数,用HPs来表示对服务器单击请求。
无论TPS、QPS、HPS,此指标是衡量系统处理能力非常重要的指标,越大越好,根据经验,一般情况下:
金融行业:1000TPS~50000TPS,不包括互联网化的活动
保险行业:100TPs~100000TPS,不包括互联网化的活动
制造行业:10TPS~5000TPS
互联网电子商务:10000TPS~1000000TPS
互联网中型网站:1000TPS~50000TPS
互联网小型网站:500TPS~10000TPS
最大响应时间(Max Response Time)指用户发出请求或者指令到系统做出反应(响应)的最大时间。
最少响应时间(Mininum ResponseTime)指用户发出请求或者指令到系统做出反应(响应)的最少时间。
90%响应时间(90%Response Time)是指所有用户的响应时间进行排序,第90%的响应时间。
从外部看,性能测试主要关注如下三个指标
吞吐量:每秒钟系统能够处理的请求数、任务数。
响应时间:服务处理一个请求或一个任务的耗时。
错误率:一批请求中结果出错的请求所占比例。
=========================================================================
微服务
微服务是分布式架构的一种,把服务做拆分,拆分时会产生各种问题
根据业务功能模块拆分,每个模块完成一部分业务功能
所以需要注册中心,记录各个模块的ip,方便模块间的调用(nacos:)
nacos负载均衡,设置集群,模块间调用时设置优先调用本地的模块服务,实现负载均衡
还需要配置中心,去管理各个模块的配置(SpringCloudConfig)
还需要服务网关组件 去调度用户要去访问哪一个模块(springcloudgateway)(请求路由,负载均衡)
在网关中可以配置过滤器
服务远程调用 Feign协议 (声明式http客户端)
GitHub - OpenFeign/feign: Feign makes writing java http clients easier
分布式缓存数据库 做数据缓存 解决系统的高并发问题(redis集群)
分布式搜索 做数据的快速检索
异步通信的消息队列组件 微服务分布,导致每个请求的链路很长,性能下降,采用消息队列缩短链路,解决系统的高并发问题(rabbitmq 流量削峰)
分布式日志服务 做日志记录
系统监控链路追踪和保护(sentinel)
持续集成 最后还需要做自动化部署,Jenkins对微服务进行自动化编译,然后就可以docker打包镜像,再基于kubernetes或者rancher技术进行自动化部署。
安全框架 Shiro
访问权限
一般表示你能做什么样的操作,或者能够访问那些资源。例如:给张三赋予“店铺主管"角色,“店铺主管”具有“查询员工”、“添加员工”、“修改员工”和“删除员工"权限。此时张三能够进入系统,则可可以进行这些操作
数据权限
一般表示某些数据你是否属于你,或者属于你可以操作范围。例如:张三是"店铺主管"角色,他可可以看他手下客服人员所有的服务的买家订单信息,他的手下只能看自己负责的订单信息
什么是认证
身份认证,就是判断一个用户是否为合法用户的处理过程。最常用的简单身份认证方式是系统通过核效对用户输入的用户名和口令,看其是否与系统中存储的该用户的用户名和口令一致,来判断用户身份是否正确。例如:密码登录,手机短信验证、三方授权等
什么是授权
授权,即访问控制,控制谁能访问哪些资源。主体进行身份认证后,系统会为其分配对应的权限,当访问资源时,会校验其是否有访问此资源的权限。
这里首先理解4个对象。
用户对象user:当前操作的用户、程序。
资源对象resource:当前被访问的对象
角色对象role:一组"权限操作许可权"的集合。
权限对象permission:权限操作许可权
快速搜索技术elasticsearch(ES)
eg:gitee开源仓库搜索;淘宝商品搜索
=======================================================================
C++ 设计模式:拦截器模式
#include<iostream>
#include<string>
#include<list>
using namespace std;
//创建过滤器抽象接口类Filter
class Filter
{
public:
Filter() {};
virtual ~Filter() {};
virtual void execute(string request)=0;
};
//创建过滤器实体类AuthenticationFilter
class AuthenticationFilter :public Filter
{
public:
AuthenticationFilter() {};
~AuthenticationFilter() {};
void execute(string request);
};
void AuthenticationFilter::execute(string request)
{
cout << "AuthenticationFilter request: " << request << endl;
}
//创建过滤器实体类DebugFilter
class DebugFilter :public Filter
{
public:
DebugFilter() {};
~DebugFilter() {};
void execute(string request);
};
void DebugFilter::execute(string request)
{
cout << "DebugFilter request: " << request << endl;
}
//创建请求处理程序Target类
class Target
{
public:
Target() {};
~Target() {};
void execute(string request);
};
void Target::execute(string request)
{
cout << "Target request: " << request << endl;
}
//创建过滤器链,将多个过滤器实体对象连接起来,实现更强大的过滤功能
class FilterChain
{
public:
FilterChain() {};
~FilterChain();
void addFilter(Filter *filter);
void execute(string request);
void setTarget(Target *target);
private:
list<Filter*> filterList;
Target *target;
};
FilterChain::~FilterChain()
{
list<Filter*>::iterator it;
for (it = this->filterList.begin(); it != this->filterList.end(); ++it)
{
delete (*it);
(*it) = NULL;
}
delete this->target;
this->target = NULL;
}
void FilterChain::addFilter(Filter *filter)
{
this->filterList.push_back(filter);
}
void FilterChain::execute(string request)
{
list<Filter*>::iterator it;
for (it = this->filterList.begin(); it != this->filterList.end(); ++it)
{
(*it)->execute(request);
}
this->target->execute(request);
}
void FilterChain::setTarget(Target *target)
{
this->target = target;
}
//创建过滤器管理类FilterManager,主要是管理过滤器链,负责增删改查过滤器链
class FilterManager
{
public:
FilterManager(Target *target);
~FilterManager();
void setFilter(Filter *filter);
void filterRequest(string request);
private:
FilterChain *filterchain;
};
FilterManager::FilterManager(Target *target)
{
this->filterchain = new FilterChain();
this->filterchain->setTarget(target);
}
FilterManager::~FilterManager()
{
delete this->filterchain;
this->filterchain = NULL;
}
void FilterManager::setFilter(Filter *filter)
{
this->filterchain->addFilter(filter);
}
void FilterManager::filterRequest(string request)
{
this->filterchain->execute(request);
}
//创建客户端Client
class Client
{
public:
Client() {};
~Client() {};
void setFilterManager(FilterManager *filterManager);
void sendRequest(string request);
private:
FilterManager *filtermanager;
};
void Client::setFilterManager(FilterManager *filterManager)
{
this->filtermanager = filterManager;
}
void Client::sendRequest(string request)
{
this->filtermanager->filterRequest(request);
}
int main()
{
FilterManager *filtermanager = new FilterManager(new Target());
filtermanager->setFilter(new AuthenticationFilter());
filtermanager->setFilter(new DebugFilter());
Client *client = new Client();
client->setFilterManager(filtermanager);
client->sendRequest("Home");
delete filtermanager;
filtermanager = NULL;
delete client;
client = NULL;
system("pause");
return 0;
}