阿里巴巴云商城–一业务架构知识学习

架构

1.云商城架构学习

2.基础数据管理,分布式文件管理

3.高性能门户首页构建

4.海量数据搜索实现

5.详情页实战

6.购物车、订单

7.分布式事务解决方案

8.微信支付

9.商品秒杀-数据处理

10.商品秒杀-热点数据实时发现系统

11.商品秒杀-程序隔离解决方案

12.官网鉴权

13.生产环境灾难控制

14.百万并发站点构建

业务架构环境

电商模式

业务学习

云商城架构

云商城表结构

搭建环境

增删改查实现

业务功能

商品增删改查

参数增删改查

订单增删改查

列表分类,首页广告(考虑并发)

动态搜索条件-es

加入购物车

用户登录

选择指定商品,进行下单

支付

秒杀并发量

秒杀商品流量控制

前后端分离开发模式

js-html-jsp

vue,elementUI,nodeJS

用swagger定义接口,开发restful接口,最后更改接口路径

image-20210818225523479

swagger的使用

云商城技术架构讲解

用户—lvs400w—ngnix5w—gateway网关(限流,建权)—后端微服务—分布式事务—数据库

云商城技术架构

客户端

  • PC H5 小程序 Android IOS

接入层

  • 心跳切换VIP: keepalived keepalived keepalived keepalived
  • 四层负载: LVS集群 LVS集群 LVS集群 LVS集群
  • 七层负载: Nginx集群 Nginx集群 Nginx集群 Nginx集群

网关层

  • 应用网关: Gateway Filter Gateway Router Gateway鉴权 Gateway限流

    ​ 水平拓展

服务层

  • 商品服务 订单服务 用户服务 搜索服务 秒杀服务

​ SpringCloud Alibaba技术栈

数据同步

  • ES搜索数据同步 热门数据同步 缓存数据同步 静态页同步 Proxy缓存同步

服务治理

  • 服务主册 服务发现 统一配置 服务熔断 服务限流

数据处理

  • MySQL Redis6.x高速缓存 Ceph分布式文件存储 ElasticSearch千亿级数据 Apache Druid千亿日志析

  • Kafka实时日志收集 RocketMQ统一消息处理 XXL-Job分布式 事务 MongoDB购物车永久保存

第三方接口

  • 短信通道 支付通道

​ 微信、阿里云短信平台

云商城表结构分析

集中式架构—-一个数据库

分布式架构——对业务进行拆分

订单明细

秒杀表

商品公共表

商品单独表

项目开发准备环境

redis cluster,ES,springcloud alibaba nacos,MySQL5.7,docker

image-20210820000137587

image-20210820000339972

项目结构详解

rabbitmq操作指南

消费者

  • 创建工厂(host,port,virtualhost,username,password)
  • 创建连接
  • 创建channel
  • 调用channel

消费者方法:channel.basicConsume(,,)

消费者创建mq配置:channel.exchangeDeclare;channel.queueDeclare;channel.queueBind

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//1.创建工厂
ConnectionFactory factory = new ConnectionFactory();
// 连接IP
factory.setHost("192.168.1.128");
// 默认监听端口
factory.setPort(5672);
// 虚拟机
factory.setVirtualHost("/");

// 设置访问的用户
factory.setUsername("admin");
factory.setPassword("admin");
// 2.建立连接
Connection conn = factory.newConnection();
// 3.创建消息通道
Channel channel = conn.createChannel();

// 创建消费者
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body) throws IOException {
String msg = new String(body, "UTF-8");
System.out.println("Received message : '" + msg + "'");
System.out.println("consumerTag : " + consumerTag );
System.out.println("deliveryTag : " + envelope.getDeliveryTag() );
}
};


// 4.开始获取消息
// String queue, boolean autoAck, Consumer callback
channel.basicConsume(QUEUE_NAME, true, consumer);

生产者

  • 创建工厂
  • 创建连接
  • 创建通道
  • 发送消息

生产者方法:channel.basicpublish(,,)

生产者必须关闭通道和连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//1.创建工厂
ConnectionFactory factory = new ConnectionFactory();
// 连接IP
factory.setHost("192.168.1.128");
// 连接端口
factory.setPort(5672);
// 虚拟机
factory.setVirtualHost("/");
// 用户
factory.setUsername("admin");
factory.setPassword("admin");

// 2.建立连接
Connection conn = factory.newConnection();
// 3.创建消息通道
Channel channel = conn.createChannel();

// 4.发送消息
String msg = "Hello world, Rabbit MQ";

// String exchange, String routingKey, BasicProperties props, byte[] body
channel.basicPublish(EXCHANGE_NAME, "gupao.best", null, msg.getBytes());

channel.close();
conn.close();

队列删除

1
2
channel.queueDelete
channel.exchangeDelete

死信队列

image-20210817010215043

生产者抛消息给队列,队列没有消息,队列绑定了过期的exchange或者queue,消息里面有设置过期时间,过期后就把消息丢给对应的exchange或者queue

启用插件

rabbitmq-plugins enable rabbitmq_management

rabbitmq 工作模型

image-20210814110251211

生产者–channel–broker–channel–consumer

broker里面的queue是放在erlang写的Mnesia数据库里面

1
2
3
4
5
6
7
8
9
while{

channel.basicGet();

}

channel.basicPublish(msg);

channel.basicPublish(flag,msg);

exchange来路由消息

vhost

Exchange路由消息详解

直连类型

![image-20210814141557476](C:\Users\admin\Desktop\rabbitmq 工作模型\image-20210814141557476.png)

消息的路由键:routing key

channel.basicPublish(exc_name,”spring”,”msg1”);

exc_name:exchange直连交换机名称

spring:routing key

msg1:消息内容

路由键==绑定建

topic主题

*一个单词

#0个或者多个单词

routing key可以带通配符

fanout广播

routing key为空

所有绑定exchange的queue都会收到消息

rabbitmq的基本使用

1.引入依赖

2.消费者

3.生产者

4.

rabbitmq与erlang安装

版本关系

1、RabbitMQ依赖于Erlang,需要先安装Erlang
2、Erlang和RabbitMQ版本有对应关系
http://www.rabbitmq.com/which-erlang.html

image.png

下载安装Erlang 23.1

如果下载太慢了,可以把地址贴到迅雷里面,下载到本机

https://www.erlang.org/downloads/23.1
exe文件一路next就可以

配置Erlang环境变量

1
ERLANG_HOME=C:\Program Files\erl23.1

Path添加

1
%ERLANG_HOME%\bin;

CMD输入 erl,输入能显示版本号则安装正确

下载安装RabbitMQ 3.8.9

http://www.rabbitmq.com/install-windows.html

RabbitMQ 环境变量

1
RABBITMQ_SERVER=C:\Program Files\RabbitMQ Server\rabbitmq_server-3.8.9

在Path中加入

1
%RABBITMQ_SERVER%\sbin;

启用RabbitMQ管理插件

CMD中输入

1
"C:\Program Files\RabbitMQ Server\rabbitmq_server-3.8.9\sbin\rabbitmq-plugins.bat" enable rabbitmq_management

启动RabbitMQ

1
net start RabbitMQ

关闭RabbitMQ

1
net stop RabbitMQ

访问管理界面:http://localhost:15672/
默认用户名:guest
默认密码为:guest

默认配置文件:

1
C:\Users\你的用户名\AppData\Roaming\RabbitMQ\advanced.config

数据目录:

1
C:\Users\用户名\AppData\Roaming\RabbitMQ\db\rabbit@用户名-mnesia

附:
如果遇到无法启动的问题,先尝试在控制面板 —— 服务 —— 中启动。
如果已经启动了,先服务里面停掉
或者尝试用命令

1
2
.\rabbitmq-server.bat stop
.\rabbitmq-server.bat start

注意只能用CMD,不要用powershell

如果要初始化RabbitMQ,移除全部数据:

1
2
3
4
rabbitmq-service stop
rabbitmq-service remove
rabbitmq-service install
rabbitmq-service start

rabbit mq连接失败

1
2
3
4
5
6
7
8
9
10
11
12
13
ConnectionFactory factory = new ConnectionFactory();
// 连接IP
factory.setHost("192.168.1.128");
// 默认监听端口
factory.setPort(15672);
// 虚拟机
factory.setVirtualHost("/");

// 设置访问的用户
factory.setUsername("admin");
factory.setPassword("admin");
// 建立连接
Connection conn = factory.newConnection();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
"C:\Program Files\java\jdk1.8.0_91\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2.4\lib\idea_rt.jar=54668:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\java\jdk1.8.0_91\jre\lib\charsets.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\deploy.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\ext\access-bridge-64.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\ext\cldrdata.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\ext\dnsns.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\ext\jaccess.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\ext\jfxrt.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\ext\localedata.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\ext\nashorn.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\ext\sunec.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\ext\sunjce_provider.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\ext\sunmscapi.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\ext\sunpkcs11.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\ext\zipfs.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\javaws.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\jce.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\jfr.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\jfxswt.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\jsse.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\management-agent.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\plugin.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\resources.jar;C:\Program Files\java\jdk1.8.0_91\jre\lib\rt.jar;D:\study\mq\gupaoedu-vip-rabbitmq-javaapi\target\classes;D:\repository\com\rabbitmq\amqp-client\5.6.0\amqp-client-5.6.0.jar;D:\repository\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar;D:\repository\org\slf4j\slf4j-simple\1.7.25\slf4j-simple-1.7.25.jar" com.gupaoedu.simple.MyConsumer
Exception in thread "main" java.io.IOException
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:129)
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:125)
at com.rabbitmq.client.impl.AMQConnection.start(AMQConnection.java:375)
at com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory.newConnection(RecoveryAwareAMQConnectionFactory.java:64)
at com.rabbitmq.client.impl.recovery.AutorecoveringConnection.init(AutorecoveringConnection.java:156)
at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:1106)
at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:1063)
at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:1021)
at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:1182)
at com.gupaoedu.simple.MyConsumer.main(MyConsumer.java:29)
Caused by: com.rabbitmq.client.ShutdownSignalException: connection error
at com.rabbitmq.utility.ValueOrException.getValue(ValueOrException.java:66)
at com.rabbitmq.utility.BlockingValueOrException.uninterruptibleGetValue(BlockingValueOrException.java:36)
at com.rabbitmq.client.impl.AMQChannel$BlockingRpcContinuation.getReply(AMQChannel.java:502)
at com.rabbitmq.client.impl.AMQConnection.start(AMQConnection.java:317)
... 7 more
Caused by: java.io.EOFException
at java.io.DataInputStream.readUnsignedByte(DataInputStream.java:290)
at com.rabbitmq.client.impl.Frame.readFrom(Frame.java:91)
at com.rabbitmq.client.impl.SocketFrameHandler.readFrame(SocketFrameHandler.java:164)
at com.rabbitmq.client.impl.AMQConnection$MainLoop.run(AMQConnection.java:598)
at java.lang.Thread.run(Thread.java:745)

Process finished with exit code 1

代码如1,报错如2

报错原因,rabbit mq的15672为管理端口,使用5672端口即可。

某些情况用15672端口也行

数据淘汰与内存回收

1.定时过期:到了key的过期时间,立即删除

2.惰性过期:key被访问的时候才判断是否过期,过期则删除

3.定时过期:每隔一段时间,清除一定数量的过期的key

image-20210811192730434

maxmemory

config set maxmemory 2GB

lru:least recently used

lfu:least frequently used

实现一个lru的算法:

链表+hash

链表里面放元素,放满了就把最后面的元素给删除

redis里面是每个key保持一个时间戳,key更新时从server.lruclock拿取时间

采样的时候就删除一些数据

lfu

基于访问频率实现

image-20210811195353107

log-factor越大,计数器增长越慢

lfu-decay-time 一分钟减小1

Redis lua脚本

指令:

eval lua-script key-num

redis.call(command,key[param1,param2])

eval “redis.call(‘set’,KEYS[1],ARGV[1])” 1 qs 2673

redis的数据类型

目前官网一共有8中

strings, hashes, lists, sets, sorted sets

hyperloglogs, geospatial indexes, and streams

字符串

String

int

float

操作指令

String

指令

mset yongjie 1234 qingshan 666 EX 10 10秒过期

mset yongjie 1234 qingshan 666 PX 10 10毫秒过期

mset yongjie 1234 qingshan 666 NX 10 不存在才成功

mset yongjie 1234 qingshan 666 XX 10 存在才成功

mget yongjie qingshan

strlen qingshan

append qingshang good

getranger qingshan 0 8

incr qingshan

incrby qingshan 100

decr qingshan

decrby qingshan 100

set f 2.6

incrbyfloat f 7.3

del f

批量赋值可以保证原子性

string应用场景

1.缓存

2.分布式session

3.set NX EX分布式锁

4.incr全局ID

5.incr计数器

6.incr限流

7.位操作统计

Hash

id sno sname company
1 16666 张岩 腾讯
2 17777 王芳 百度
3 18888 刘厉 阿里

mset student:1:sno 1666 student:1:sname 张岩

hash里面value只能存储字符串

hash和string区别:

  • 用冒号去分层,减少内存的消耗

  • 减少命名的冲突

  • 一次取多个,减少资源的消耗

hash是按照key取模去做集群,如果一个key特别大,没办法分流

指令:

hset h1 f 6

redis GEO Spatial & Hyperloglogs

geo spatial

指令:

geoadd citys 121.48 21.22 sh 113.01 28.19 cs

geopos citys cs

geopos citys sh cs km

georadius citys 113.01 28.19 5 km

georadiusbymember citys cs 20 km

添加两个城市的经纬度

显示某个城市的经纬度

计算两个城市的距离

显示某个位置5km的城市

hyperloglogs

指令:

pfadd log 1 2 3 4 5 6 7 8

pfcount log

pfadd qs a b c d e f g

pfcount qs

pfmerge result log qs

应用:

统计网站用户的访问量