1 商城项目的框架
商城项目用到的技术还是非常多的,有dubbo zookeeper MQ solr redis 等等。下面逐个剖析各个技术
2 dubbo
我们使用dubbo进行服务的管理和调用,那么dubbo具体有什么作用呢?我们使用dubbo应该注意什么问题呢?
2.1 dubbo的作用
- 远程接口调用 (2)智能容错和负载均衡 (3)服务的自动注册和发现
2.2 dubbo整体的框架?
Dubbo作为服务管理和调用框架,必然有如下几种角色:
服务的提供者,服务运行容器,消费者,注册中心,监视中心,
2.3 如何实现远程接口调用
http也可以实现远程的接口调用,例如;http//localhost:8080/XXXservice。但是,很明显这种调用是非常的麻烦的。我们要写死服务的IP地址和端口以及接口的名字。Dubbo克服了这个问题,在开发的时候,我们不用关注IP地址和端口,直接调用接口即可。Dubbo使用的是RPC来进行服务之间的调用的。我们只用关注接口,序列化和反序列化,服务之间的通信都已经封装好了。
为什么使用rpc协议而不直接使用http协议?
-
传输效率
- RPC,使用自定义的TCP协议,可以让请求报文体积更小,或者使用HTTP2协议,也可以很好的减少报文的体积,提高传输效率
- HTTP,如果是基于HTTP1.1的协议,请求中会包含很多无用的内容,如果是基于HTTP2.0,那么简单的封装以下是可以作为一个RPC来使用的,这时标准RPC框架更多的是服务治理
-
性能消耗,主要在于序列化和反序列化的耗时
- RPC,可以基于thrift实现高效的二进制传输
- HTTP,大部分是通过json来实现的,字节大小和序列化耗时都比thrift要更消耗性能
总结:
RPC主要用于公司内部的服务调用,性能消耗低,传输效率高,服务治理方便。HTTP主要用于对外的异构环境,浏览器接口调用,APP接口调用,第三方接口调用等。
2.4 智能容错
我们知道dubbo可以容错,那么具体是如何实现的呢?当然,容错是你对服务建立了集群。
2.5 负载均衡的实现
在 Provider 上可以配置的 Consumer 端的属性有哪些?
1)timeout:方法调用超时
2)retries:失败重试次数,默认重试 2 次
3)loadbalance:负载均衡算法,默认随机
4)actives 消费者端,最大并发调用限制
常用的负载均衡算法:
(1) 基于权重随机算法的 RandomLoadBalance加权轮询
A B C 三台 权重分别为 5 3 2 那么A的服务器[0,5] B [5,8] C[8,10] 0-10产生随机数
(2) 基于最少活跃调用数算法的 LeastActiveLoadBalanceHash
能者多劳,处理的越快,分配给该服务器的任务就越多
(3) 基于 hash 一致性的
一个[0,2^32-1]槽点的hash环,我们把服务器hash()%2^32分布到不同的槽点上。当请求来的时候,我们对其hash之后映射到环上。顺时针旋转到的服务器就是该 请求要访问的服务器。传统的hash算法需要重新计算所有数据的hash值,然后重新分配,涉及到的迁移数据将会是全部数据。一致性哈希算法优化的点也是在于这里,如果当前节点挂了,其实需要重新写入的也只有这个节点的数据,当这个节点的数据直接迁移到下一个大于其hash值得机器节点即可。只有部分的数据失效。
数据倾斜是指,由于节点不够分散,导致大量请求落到了同一个节点上,而其他节点只会接收到了少量请求的情况。怎么解决?
引入虚拟节点。那什么是虚拟节点呢?其实个人的理解如果说实际的节点是通过真实机器的真实信息的一个hash映射,那么虚拟节点无非是在真实机器中划分一个虚拟区域的信息,然后将真实机器的hash映射做一个细分。
举个例子,如果我们按照真实机器的ip进行hash化,从而在哈希环中做了一个节点的投射,那么虚拟节点我们以采用ip加数据后缀的方式,投射出虚拟节点在哈希环的位置。加入了虚拟节点,可以让数据的分布更加平衡。
(4) 基于加权轮询
这种算法的原理是:在服务器数组S中,首先计算所有服务器权重的最大值max(S),以及所有服务器权重的最大公约数gcd(S)。index表示本次请求到来时,选择的服务器的索引,初始值为-1;current_weight表示当前调度的权值,初始值为max(S)。当请求到来时,从index+1开始轮询服务器数组S,找到其中权重大于current_weight的第一个服务器,用于处理该请求。记录其索引到结果序列中。在轮询服务器数组时,如果到达了数组末尾,则重新从头开始搜索,并且减小current_weight的值:current_weight -= gcd(S)。如果current_weight等于0,则将其重置为max(S)。
2.6 Dubbo启动时如果依赖的服务不可用会怎样?
Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,默认 check="true",可以通过 check="false" 关闭检查。
2.7 Dubbo可以对结果进行缓存吗?
可以,Dubbo 提供了声明式缓存,用于加速热门数据的访问速度,以减少用户加缓存的工作量。
2.8 Dubbo的直连,绕过注册中心
3 ActiveMQ
消息队列来传递消息,包含点到点和发布订阅模式
3.1 作用
(1)服务之间解耦
(2)异步传输
(3)削峰
3.2 ActiveMQ消息持久化
KahaDB:和redis的AOF类似,日志形式存储消息;
使用JDBC持久化方式,数据库默认会创建3个表,每个表的作用如下:
activemq_msgs:queue和topic的消息都存在这个表中
activemq_acks:存储持久订阅的信息和最后一个持久订阅接收的消息ID
activemq_lock:跟kahadb的lock文件类似,确保数据库在某一时刻只有一个broker在访问
3.3 队列满了怎么办?
队列满了,可以使用临时表,把溢出的数据放到临时表里。
3.4 消息的确认
队列 会出现阻塞和丢失
我怎么知道哪些丢失了?MQ你要给我确认是否发送成功了?
给message添加ID属性,通过回调函数记录发送失败和成功的消息的ID
3.5 消息重发
事务回滚或者事务未提交,就好比快递员送货到门,但是,我不在,你过一段时间再来。过后再来,发现还不在,那再过一段时间再来。
快递员隔多长时间来一次,最多来多少次?
间隔:1S 重发:6次
快递员肯定不能无限次的给你送快递,当尝试了6次还不成功,直接就把你的这个快递丢垃圾桶里了。
消息重发了6次,还不成功。消费端会给MQ发一个”poison ack”表示这个消息有毒,直接把这个消息放入死信队列。
3.6 死信队列
消息重发多次进入死信队列,人去查看异常消息
3.7 消息的重复消费
不要重复消费,这种情况出现在网络延迟的时候,出现重传。往消息队列中存放数据,如何插入到数据库,我们不能插入两条一样的消息。
给消息设置ID属性,当消息被消费了,我们就通过<id,message>把消息存到redis里面去。当消费的时候,去redis中查看消费的记录,有了说明重复消费。
4 redis
Redis是非常作用的,我们用reids做缓存,添加分布式锁,添加分布式事务
4.1 Redis几种数据类型
String、List、Set、Sorted Set、hashes
(1)String
缓存,计数
(2)hash
SSO 单点登录存放用户信息
(3)List
列表信息,消息队列
List作为消息队列存在问题。
如果,队列为空,队列空后,客户端就会陷入pop的死循环。我们可以sleep()一段时间,但是,这个时间难以确定。使用阻塞队列,pop不成功就进队列,当往list中添加数据之后就唤醒。如果线程一直阻塞在哪里,Redis的客户端连接就成了闲置连接,闲置过久,服务器一般会主动断开连接,减少闲置资源占用。
(4)set
set可以求交集,并集,差集
(5)sortedset
排行榜
4.2 Redis设置过期时间
(1)定时删除
一定时间间隔内,随机抽取设置了过期时间的Key,如果,过期就删除
(2)惰性删除
定时删除的时候,没有删除的情况下,当系统检查的时候,才进行删除
4.3 内存淘汰
(1)设置了过期时间 lru 最长最久未使用的数据 ttl 将要过期的数据 random 随机选择
(2)没有设置过期时间 内存不足时,移除最少使用的key。Random 随机选择
4.4 Redis集群方案
Redis集群没有使用一致性hash,而是引入了哈希槽的概念,Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。
4.5 Redis缓存穿透,缓存雪崩
缓存穿透:
- 增加校验
- 访问一个不存在的数据,可以设置一个key-null存到缓存中,并且设置一个较短的生命周期
- 布隆过滤器
缓存雪崩
- 过期时间随机设置
- 热点数据永不过期
- 热点数据分布到不同的分布式服务器上
4.6 Redis持久化
RDB
单个时间间隔内写到达一定的数量
缺点:
(1)占用内存,开辟一个子进程,复制数据到临时文件,把临时文件替换之前的备份文件。
(2)可用性一致性不高,如果最后一次备份的时候宕机了,最后一次数据没有备份
AOF
记录redis操作
缺点:
文件越来越大,数据恢复也越来越慢
4.7 Redis缓存一致性
延时双删策略
(1)先删除缓存
(2)改写数据库
休眠一段时间,确保读彻底结束
(3)再删除缓存
4.8 Redis分布式锁
使用redsssion框架,分布式锁比较简单
setNx实现分布式锁,set(key)获取锁,其他设置key值得都不能成功。
注意点:
(1)设置过期时间,为了保证原子性,jdk提供了(key,过期时间)的原子操作
(2)看门狗默认30秒去检查一次锁的超时时间,会对锁的过期时间进行延长
4.9 Redis分布式事务
(1)2PC
第一阶段:预操作,修改订购状态,减少库存,但是,不提交。把状态都提交给事务管理器
第二阶段:当每个操作都成功了,才提交。否则,取消。
(2)TCC (try-confrim-cancel)
第一阶段:预操作,修改订单状态,count (frozen 1)冻结。事务提交
第二阶段:如果都成功了,confirm提交,否则,取消。
5 Spring
5.1 设计原则
1 开闭原则
2 单一职责原则
3 高内聚 低耦合
4 多用组合,少用继承
5 面向接口编程
5.2 Spring用到的设计模式
- 工厂模式:bean工厂
- 单例模式:bean默认是单例的
- 模板模式:jdbctemplate hibernatetemplate
- 代理模式: spring AOP
- 观察者模式: Spring中listener的实现
等等
5.3 Bean的生命周期
- 通过构造器或工厂方法创建 Bean 实例
- 为 Bean 的属性设置值和对其他 Bean 的引用
- 调用 Bean 的初始化方法
- Bean 可以使用了
- 当容器关闭时, 调用 Bean 的销毁方法
请解释Spring Bean的生命周期?
首先说一下Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy;
Spring上下文中的Bean生命周期也类似,如下:
(1)实例化Bean:
对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。
(2)设置对象属性(依赖注入):
实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。
(3)处理Aware接口:
接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:
①如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值;
②如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。
③如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;
(4)BeanPostProcessor:
如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。
(5)InitializingBean 与 init-method:
如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
(6)如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;
以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。
(7)DisposableBean:
当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;
(8)destroy-method:
最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。 Spring是一个轻量级的IoC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用程序的开发,它使得开发者只需要关心业务需求。常见的配置方式有三种:基于XML的配置、基于注解的配置、基于Java的配置。
5.4 Spring的核心模块
主要由以下几个模块组成:
Spring Core:核心类库,提供IOC服务;
Spring Context:提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等);
Spring AOP:AOP服务;
Spring DAO:对JDBC的抽象,简化了数据访问异常的处理;
Spring ORM:对现有的ORM框架的支持;
Spring Web:提供了基本的面向Web的综合特性,例如多方文件上传;
Spring MVC:提供面向Web应用的Model-View-Controller实现。
6 mybatis
7 常见的业务问题
7.1 单点登录
一次登录,多次使用
- 登录之后,各个服务都可以获取登录的信息
- 内容服务可以在商城门户界面显示用户名
- 商品服务可以获得用户名,把商品添加到购物车
- 订单服务可以获取用户名,生成订单
7.2 购物车
为登录:
保存到cookie
登录:
保存到redis,采用哪种数据结构存储,使用的是hash
显示的时候:
Cookie和Redis中的商品信息进行合并
7.3 消息队列
大量的inser,update之类的请求同时到达数据库mysql,会产生大量的行锁和表锁,导致请求堆积。触发错误 太多连接。
- 更新搜索系统库
- 订单—》支付—》库存
生成订单,写入数据库,涉及到IO。就不能立马跳到支付页面支付。
提交订单,直接把订单写入消息队列,不用等待,之后再调用订单服务写入数据库
支付成功,库存操作写入消息队列,不用等待,之后调用库存服务操作数据库
7.4 solr
基于分词技术构建倒排索引进行查询
7.5 Redis
String 类型 首页缓存,秒杀系统的限流计数
Hash SSO登录对象的保存,购物车商品信息保存
Zset 商品按照价格进行排名
8 Http
8.1 HTTP的构成
请求
请求行:请求方法,URL,http版本
请求方法:get post put delete head options 等
- GET: 用于请求访问已经被URI(统一资源标识符)识别的资源,可以通过URL传参给服务器
- POST:用于传输信息给服务器,主要功能与GET方法类似,但一般推荐使用POST方式。
- PUT: 传输文件,报文主体中包含文件内容,保存到对应URI位置。
- HEAD: 获得报文首部,与GET方法类似,只是不返回报文主体,一般用于验证URI是否有效。
- DELETE:删除文件,与PUT方法相反,删除对应URI位置的文件。
- OPTIONS:查询相应URI支持的HTTP方法。
请求头:
User-Agent: 客户端和操作系统的信息
Host:资源所在的服务器
Accept-Language:可接受的语言
空行:
请求体:
响应
状态行:
1XX:信息响应类,表示接收到请求并且继续处理。
2XX:处理成功响应类,表示动作被成功接收、理解和接收
3XX:重定向响应类,表示为了完成指定的动作,必须接受进一步处理
4XX:客户端错误,表示客户请求包含语法错误或不能正确执行
5XX:服务端错误,表示服务器不能正确执行一个正确的请求
400:请求有语法错误
403:禁止访问
404:页面不存在
500:服务器内部错误
503:服务器不可用稍等
响应报头
Date:创建报文时间
Server: HTTP服务器的安装信息
Content-Range:实体主体的位置范围,一般用于发出部分请求时使用
Content-Length:实体主体的的字节数
Content-Type:实体主类的类型
Content-Encoding:实体主体适用的编码方式
Content-Language:实体主体的自然语言
空行
响应正文
8.2 HTTP的请求过程
- 域名解析,把域名解析成IP地址
- 有了IP地址,通过三次握手建立TCP/IP连接
- 有了TCP/IP连接,浏览器想服务器端发起http请求
- 服务器端接收到http请求,根据请求的路径参数找到对应的服务器处理器处理该请求,把处理结果和响应的视图返回给客户端
- 客户端解析并渲染视图,如果遇到css,js,图片等静态资源重复上诉步骤来获取资源
- 浏览器根据请求到的资源、数据渲染页面,呈现给用户完整的页面
8.3 HTTPS的原理
HTTP为什么不安全?
明文传输
我们可以对称加密啊?
黑客可以获取秘钥和传输数据,依然可以获取传输数据
那我们可以非对称加密啊?
客户端发送的数据,黑客无法获取私钥,确实保证了安全,但是,服务器端向客户端发送数据也是可以被获取的
那我们可以对称加密+非对称加密
我们使用非对称加密对对称加密的秘钥进行加密传送,然后,使用对称加密的秘钥对传输的数据进行加密。客户端利用公钥对对称加密的秘钥进行加密,然后,发送给服务器。这看似是无懈可击了,但是,中间人攻击可以对非对称加密发起攻击,给客户端一个假的公钥。
那我们可以对称加密+非对称加密+CA认证机构
既然是签名,那肯定是不希望有人冒充我发消息,只有我才能发布这个签名,所以可得出私钥负责签名,公钥负责验证。
CA通过秘钥对要发送的公钥进行加密,生成证书。把这个证书传给客户端。客户端获取了证书,通过本地存的公钥对这个证书进行验证,查看公钥是否安全。
8.4 DNS工作过程
- 浏览器中DNS缓存,操作系统的DNS缓存,本地host文件,本地的DNS服务器。
- 如果,由本地的DNS服务器进行解析,则将结果返回给客户机
- 如果不是由本地DNS服务器进行解析,但是,本地服务器已经缓存了该网址映射关系,则返回IP地址
- 如果,都没找到,则询问根服务器,找到具体的对域名解析的DNS服务器
9 Zookeeper
9.1 Zookeeper 概念
为分布式应用服务提供协调服务
分布式应用中的数据管理:配置管理,域名管理,分布式同步,集群管理
9.2 Zookeeper组成
文件系统、通知机制
文件系统:树形结构存储数据,每个节点成为Znode.每个节点都有唯一的路径,如/app1/app2. 只存放配置信息。
节点的类型:
- 持久化目录节点:客户端与服务器端端口连接,该节点依然存储
- 持久化顺序编号节点:客户端与服务器端断开连接,此节点被编号
- 临时节点:客户端与服务器端端口,节点不存在
- 临时顺序编号的节点:客户端和服务器端断开连接,节点删除 但是会被编号
通知机制
基于观察者模式,服务器注册到zookeeper,客户端订阅。当服务器节点增加和减少,或者节点中的数据发生了变化,都会通知服务器端。
9.3 Zookeeper的应用