你真的了解商城项目吗?
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来进行服务之间的调用的。我们只用关注接口,序列化和反序列化,服务之间的通信都已经封装好了。
2.4 智能容错
我们知道dubbo可以容错,那么具体是如何实现的呢?当然,容错是你对服务建立了集群。
2.5 负载均衡的实现
在 Provider 上可以配置的 Consumer 端的属性有哪些?
1)timeout:方法调用超时
2)retries:失败重试次数,默认重试 2 次
3)loadbalance:负载均衡算法,默认随机
4)actives 消费者端,最大并发调用限制
常用的负载均衡算法:
- 基于权重随机算法的 RandomLoadBalance加权轮询
A B C 三台 权重分别为 5 3 2 那么A的服务器[0,5] B [5,8] C[8,10] 0-10产生随机数
- 基于最少活跃调用数算法的 LeastActiveLoadBalanceHash
能者多劳,处理的越快,分配给该服务器的任务就越多
- 基于 hash 一致性的
一个[0,2^32-1]槽点的hash环,我们把服务器hash()%2^32分布到不同的槽点上。当请求来的时候,我们对其hash之后映射到环上。顺时针旋转到的服务器就是该 请求要访问的服务器。传统的hash算法需要重新计算所有数据的hash值,然后重新分配,涉及到的迁移数据将会是全部数据。一致性哈希算法优化的点也是在于这里,如果当前节点挂了,其实需要重新写入的也只有这个节点的数据,当这个节点的数据直接迁移到下一个大于其hash值得机器节点即可。只有部分的数据失效。
数据倾斜是指,由于节点不够分散,导致大量请求落到了同一个节点上,而其他节点只会接收到了少量请求的情况
怎么解决?
引入虚拟节点。那什么是虚拟节点呢?其实个人的理解如果说实际的节点是通过真实机器的真实信息的一个hash映射,那么虚拟节点无非是在真实机器中划分一个虚拟区域的信息,然后将真实机器的hash映射做一个细分。
举个例子,如果我们按照真实机器的ip进行hash化,从而在哈希环中做了一个节点的投射,那么虚拟节点我们可以采用ip加数据后缀的方式,投射出虚拟节点在哈希环的位置。加入了虚拟节点,可以让数据的分布更加平衡。
- 基于加权轮询
1:普通加权轮询算法
这种算法的原理是:在服务器数组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.2 将商品添加到索引库
监听商品添加消息,接收消息,将对应的商品信息同步到索引库每次添加完商品并将同步商品到索引库如果,如果直接同步数据库,当数据库很大的时候,会影响服务器性能,这时我们,就使用ActiveMQ消息中间件,后台添加完消息后,搜索服务器发送一个消息【商品id】,并将接收到的商品id在数据库中查找跟商品id有关的信息,把信息添加到索引库中。
3.3 ActiveMQ消息发送失败
点到点:发送失败,服务端会把消息保存起来,直到客户端消费
发布和订阅:每个订阅端定义一个id,在订阅是向ActiveMQ注册,发布消息和接受消息时需要配置发送模式为持久化,此时如果客户端接受不到消息,消息会持久化到服务端,直到客户端正常接收后为止。
3.4 如何防止消息重复发送
使用消息状态表,消息发送之前,检查消息的状态,防止重复发送
3.5 队列满了怎么办?
队列满了,可以使用临时表,把溢出的数据放到临时表里。
4 redis
Redis是非常作用的,我们用reids做缓存,添加分布式锁,添加分布式事务
4.1 Redis几种数据类型
String、List、Set、Sorted Set、hashes
- String
缓存,计数
- hash
SSO 单点登录存放用户信息
- List
列表信息,消息队列
List作为消息队列存在问题。
如果,队列为空,队列空后,客户端就会陷入pop的死循环。我们可以sleep()一段时间,但是,这个时间难以确定。使用阻塞队列,pop不成功就进队列,当往list中添加数据之后就唤醒。如果线程一直阻塞在哪里,Redis的客户端连接就成了闲置连接,闲置过久,服务器一般会主动断开连接,减少闲置资源占用。
- set
set可以求交集,并集,差集
- 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 zookeeper
5.1 选举算法和流程
目前有5台服务器,每台服务器均没有数据,它们的编号分别是1,2,3,4,5,按编号依次启动,它们的选择举过程如下:
服务器1启动,给自己投票,然后发投票信息,由于其它机器还没有启动所以它收不到反馈信息,服务器1的状态一直属于Looking(选举状态)。
服务器2启动,给自己投票,同时与之前启动的服务器1交换结果,由于服务器2的编号大所以服务器2胜出,但此时投票数没有大于半数,所以两个服务器的状态依然是LOOKING。
服务器3启动,给自己投票,同时与之前启动的服务器1,2交换信息,由于服务器3的编号最大所以服务器3胜出,此时投票数正好大于半数,所以服务器3成为领导者,服务器1,2成为小弟。
服务器4启动,给自己投票,同时与之前启动的服务器1,2,3交换信息,尽管服务器4的编号大,但之前服务器3已经胜出,所以服务器4只能成为小弟。
服务器5启动,后面的逻辑同服务器4成为小弟。
5.2 Zookeeper对节点的watch监听通知是永久的吗?
- 两个线程:一个监听,一个负责连接
- 注册监听器列表(路径),监听节点数据和监听节点的增减
- 一个Watch事件是一个一次性的触发器,当被设置了Watch的数据发生了改变的时候,则服务器将这个改变发送给设置了Watch的客户端,以便通知它们。
为什么不是永久的,举个例子,如果服务端变动频繁,而监听的客户端很多情况下,每次变动都要通知到所有的客户端,这太消耗性能了。
一般是客户端执行getData(“/节点A”,true),如果节点A发生了变更或删除,客户端会得到它的watch事件,但是在之后节点A又发生了变更,而客户端又没有设置watch事件,就不再给客户端发送。
在实际应用中,很多情况下,我们的客户端不需要知道服务端的每一次变动,我只要最新的数据即可。
5.3 部署方式?集群中的机器角色都有哪些?集群最少要几台机器
单机,集群。Leader、Follower。集群最低3(2N+1)台,保证奇数,主要是为了选举算法。
集群如果有3台机器,挂掉一台集群还能工作吗?挂掉两台呢?
记住一个原则:过半存活即可用。
5.4 集群支持动态添加机器吗?
其实就是水平扩容了,Zookeeper在这方面不太好。两种方式:
全部重启:关闭所有Zookeeper服务,修改配置之后启动。不影响之前客户端的会话。
逐个重启:顾名思义。这是比较常用的方式。
6 数据库表怎么设计的?
用户表,内容表,内容类型表,订单表,订单明细表,收货地址表,商品表,商品类型,商品描述