Mall商城的高级篇的开发(一)全文检索和Nginx的反向代理

Mall商城的高级篇的开发

项目的整体架构图

image-20220504212423119

实现全文检索和日志分析

在本项目中,全文检索使用ElasticSearch来做全文检索。

做日志存储和日志检索(日志的快速定位)使用ELK(ElasticSearch+Kibana+LogStash).

比如,腾讯云的ES服务器利用LogStash来进行数据传输汇聚到我们的ES中进行存储和异常定位与监控。

他会收集我们项目中日志,包括前台服务和后台服务,还有第三方的中间件

image-20220504212523588

实现全文检索

流程是这样:在我们后台管理系统中对应着有SPU管理,有一个商品上架的功能。

image-20220505081801386

通过点击商品的上架功能,我们的后台服务器将改商品的所有属性传给我们的ES服务器并在ES服务器保存(index),之后在实现我们的全文检索的功能。

其中保存商品的数据,不是说将商品的所有信息都保存在ES服务器,主要的原因是ES服务器保存的数据都在内存中,内存相对硬盘,性价比还是相差很大。

SKU在ES中的存储模型分析

当然在ES服务器中保存的是JSON数据,基于此,我们约定好需要检索的内容。

{
  "skuId":"1",
  "spuId":"11"
  "skuTitle":"Apple xx",
  "price":"99",
  "seleCount":"990"
  "attrs":[
    {"尺寸":"xx"},
    {"CPU":"xx"},
    {"分辨率":""},    
  ]
}

这样进行存储,很容易产生冗余字段。但是呢,这样检索起来方便。这个是利用空间换时间。

其实呢,为了减少冗余字段,因为每个商品的属性有的就是一样。

sku索引{
  "skuId":"1",
  "skuTitle":"Apple xx",
  "price":"99",
  "seleCount":"990"
}

attr索引{
  "spuId":"11",
  "attrs":[
   	{"尺寸":"xx"},
   {"CPU":"xx"},
   {"分辨率":""}  
  ]
}

这个使用时间换空间。

最后我们还是选择浪费时间少的存储模型。

PUT product
{
    "mappings":{
        "properties": {
            "skuId":{ "type": "long" },
            "spuId":{ "type": "keyword" },  # 不可分词
            "skuTitle": {
                "type": "text",
                "analyzer": "ik_smart"  # 中文分词器
            },
            "skuPrice": { "type": "keyword" },  # 保证精度问题
            "skuImg"  : {
      						"type": "keyword",
      						"index":false,
      						"doc_value"
    							},  
            "saleCount":{ "type":"long" },
            "hasStock": { "type": "boolean" },
            "hotScore": { "type": "long"  },
            "brandId":  { "type": "long" },
            "catalogId": { "type": "long"  },
            "brandName": {"type": "keyword"}, # 视频中有false
            "brandImg":{
                "type": "keyword",
                "index": false,  # 不可被检索,不生成index,只用做页面使用
                "doc_values": false # 不可被聚合,默认为true
            },
            "catalogName": {"type": "keyword" }, # 视频里有false
            "attrs": {
                "type": "nested",
                "properties": {
                    "attrId": {"type": "long"  },
                    "attrName": {
                        "type": "keyword",
                        "index": false,
                        "doc_values": false
                    },
                    "attrValue": {"type": "keyword" }
                }
            }
        }
    }
}

使用Nginx做动静分离和反向代理

动静分离

image-20220505164823124

用户在请求的时候,如果只是简单访问图片、html等静态资源的时候,Nginx直接返回。

如果用户发送动态请求,Nginx就会把动态请求发送给网关,网关在路由给响应的后台服务。

Nginx的动静分离简单来说就是把静态请求和动态请求分开来处理,不能简单理解成只是单纯的把动态页面和静态页面物理分离。

严格意义上来说应该是动态请求和静态请求分开,可以理解成使用Nginx处理静态请求,使用Tomcat处理动态请求。

动静分离从目前的实现角度,大致分为两种:

  • 一种是单纯的把静态文件独立成单独的域名,放在独立的服务器上,也是目前主流的实现方案。
  • 另外一种是就是动态和静态文件混合在一起发布,通过Nginx来分开。

页面开发

引入模版引擎thymeleaf

官方文档:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#what-kind-of-templates-can-thymeleaf-process

配置的步骤:

  • 关闭thymeleaf的缓存。目的是:为了在我们调式项目方便。

  • 静态资源放在static目录下

  • html页面放在templates目录下。

  • 页面修改实时更新(不重启服务器的情况下)

    • 导入devtools依赖
    <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-devtools</artifactId>
         <optional>true</optional>
    </dependency>
    
    • 重新build

    以上功能可以实现,都是因为SpringBoot的WebMvcAutoConfiguration

image-20220505172231794

反向代理

在此和几个很常见的面试题有关联:

1、在浏览器地址栏输入一个URL后回车,背后发生了什么

2、同时关于TCP三次握手和四次挥手。

后面会有专门的博客,对此内容在此讲解。

image-20220506180119389

要实现的逻辑:本机浏览器请求gulimall.com,通过配置hosts文件之后,那么当你在浏览器中输入gulimall.com的时候,相当于域名解析DNS服务解析得到ip 192.168.56.10,也就是并不是访问java服务,而是先去找nginx。

什么意思呢?是说如果某一天项目上线了,gulimall.com应该是nginx的ip,用户访问的都是nginx

请求到了nginx之后,

  • 如果是静态资源/static/* 直接在nginx服务器中找到静态资源直接返回。
  • 如果不是静态资源 /(他配置在/static/*的后面所以才优先级低),nginx把他upstream转交给另外一个ip 192.168.56.1:88这个ip端口是网关gateway。
    • (在upstream的过程中要注意配置proxy_set_header Host $host;)

到达网关之后,通过url信息断言判断应该转发给nacos中的哪个微服务(在给nacos之前也可以重写url),这样就得到了响应。

而对于openFeign,因为在服务中注册了nacos的 ip,所以他并不经过nginx。

实现负载均衡的步骤和解释

  1. Nginx+Mac搭建访问域名的访问的环境(也就是讲我们的虚拟机的IP地址配置到我们的本地域名服务器中)

Mac 的本地域名文件:

/etc/hosts

image-20220506195624230

  1. 测试结果

image-20220506195705947

  1. 实现的第一个效果

访问gulimall.com通过Nginx的反向代理将请求转到我们的商品服务(product)的index.html

此时需要我们来对Nginx进行修改它的配置文件:

image-20220506201044273

需要大概了解一下它的配置文件:

nginx.conf的配置文件的分布图:

image-20220506201557768

//======全局块=====start======
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

//======全局块=====end======

//======events块=====start======
events {
    worker_connections  1024;//每个进程的最大连接数
}
//======events块=====end======

//======http块=====start======
http {
  	//====http全局块=====start=====
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf; //包含其他的配置
    //====http全局块=====end=====
}

nginx.conf中我们不能发现它是没有server块,但是我们可以看到的是include /etc/nginx/conf.d/*.conf;

server {
listen       80; //监听我们的80端口
listen  [::]:80; 
server_name  localhost; //域名

#access_log  /var/log/nginx/host.access.log  main;

location / {
  root   /usr/share/nginx/html;
  index  index.html index.htm;
}

#error_page  404              /404.html;

# redirect server error pages to the static page /50x.html
#
error_page   500 502 503 504  /50x.html;
location = /50x.html {
  root   /usr/share/nginx/html;
}

# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
#    proxy_pass   http://127.0.0.1;
#}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
#    root           html;
#    fastcgi_pass   127.0.0.1:9000;
#    fastcgi_index  index.php;
#    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
#    include        fastcgi_params;
#}

# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
#    deny  all;
#}
}

我们需要在这一块配置,来达到我们一开始的需求:访问gulimall.com通过Nginx的反向代理将请求转到我们的商品服务(product)的index.html

我们先通过访问我们自定义的域名,可以看到它跳到我们的Nginx的80端口的index页面。

image-20220506203534120

image-20220506205253379

现在我们是希望它可以帮我们转到我们的商品服务。也就是8081/

image-20220506203933379

所以此时我们需要在server块,进行反向代理的配置。为了安全起见,我们可以选择复制一份我们的default.conf

cp default.conf gulimall.conf

所以我们针对我们的需求,对Nginx的server块,进行一个配置:

image-20220506210406780

最后呢,我们需要重启我们的Nginx服务。

docker restart nginx

测试页面,发现访问失败,开始对失败定位。

# 看一下nginx是否启动
docker ps nginx

# 看一下nginx的日志 
docker logs nginx

image-20220506211050036

说我们的第10行又问题。

image-20220506211141997

通过这个命令,可以看到我们的行数。

其实就是少了个分号。

最后还有一个错误就是格式错误:

image-20220507165855117

  1. 测试成功

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9VRpSt5b-1651930099166)(/Users/wanglufei/Library/Application Support/typora-user-images/image-20220507165956313.png)]

image-20220507165940134

  1. 改动(由于我们的后台服务后多,如果每一个服务都配置,显然是不友好的,此时我们只需要将请求带给我们的网关,让我们的网关自己去在服务的注册中心去找),也就是负载均衡到我们的网关

要实现的效果:

image-20220507170738771

使用Nginx做负载均衡配置官方文档的地址:http://nginx.org/en/docs/http/load_balancing.html

Introduction

Load balancing across multiple application instances is a commonly used technique for optimizing resource utilization, maximizing throughput, reducing latency, and ensuring fault-tolerant configurations.

在多个应用实例之间进行负载均衡是一种常用的技术,可以优化资源利用,最大限度地提高吞吐量,减少延迟,并确保容错配置。

It is possible to use nginx as a very efficient HTTP load balancer to distribute traffic to several application servers and to improve performance, scalability and reliability of web applications with nginx.

可以使用nginx作为一个非常有效的HTTP负载均衡器,将流量分配到几个应用服务器上,用nginx提高网络应用的性能、可扩展性和可靠性。

Load balancing methods(负载平衡方法)

The following load balancing mechanisms (or methods) are supported in nginx:(nginx支持下列负载平衡机制(或方法)。)

  • round-robin — requests to the application servers are distributed in a round-robin fashion,

    round-robin - 对应用服务器的请求是以轮流方式分配的。

  • least-connected — next request is assigned to the server with the least number of active connections,

    最少连接 - 将下一个请求分配给活动连接数最少的服务器。

  • ip-hash — a hash-function is used to determine what server should be selected for the next request (based on the client’s IP address).

    ip-hash - 用一个哈希函数来决定下一个请求应该选择哪个服务器(基于客户端的IP地址)。

官方提出的负载均衡最简单的实例:

http {
    upstream myapp1 { //上有服务器
        server srv1.example.com;
        server srv2.example.com;
        server srv3.example.com;
    }

    server {
        listen 80;

        location / {
            proxy_pass http://myapp1;
        }
    }
}

官方对他作出的解释:

In the example above, there are 3 instances of the same application running on srv1-srv3. When the load balancing method is not specifically configured, it defaults to round-robin. All requests are proxied to the server group myapp1, and nginx applies HTTP load balancing to distribute the requests.

在上面的例子中,有3个相同应用程序的实例在srv1-srv3上运行。当没有特别配置负载均衡方法时,它默认为轮循。所有请求都被代理到服务器组myapp1,nginx应用HTTP负载均衡来分配请求。

Reverse proxy implementation in nginx includes load balancing for HTTP, HTTPS, FastCGI, uwsgi, SCGI, memcached, and gRPC.

nginx的反向代理实现包括HTTP、HTTPS、FastCGI、uwsgi、SCGI、memcached和gRPC的负载均衡。

To configure load balancing for HTTPS instead of HTTP, just use “https” as the protocol.

要为HTTPS而不是HTTP配置负载均衡,只需使用 "https "作为协议。

When setting up load balancing for FastCGI, uwsgi, SCGI, memcached, or gRPC, use fastcgi_pass, uwsgi_pass, scgi_pass, memcached_pass, and grpc_pass directives respectively.

当为FastCGI、uwsgi、SCGI、memcached或gRPC设置负载均衡时,分别使用fastcgi_pass、uwsgi_pass、scgi_pass、memcached_pass和grpc_pass指令

进入到我们的nginx.conf配置http块:

image-20220507175728273

进入到/nginx/conf/conf.d修改我们的代理服务器:

image-20220507180623319

同时我们还需要配置网关,使用host路由断言:

- id: gulimall_host_route
          uri: lb://product
          predicates:
            - Host=**.gulimall.com

重启我们的网关服务,测试

image-20220507185239873

也就是出现了:Nginx代理到网关丢失了请求头的信息(Host)

解决办法:

需要到我们的nginx的server块,进行设置一个代理的请求头的信息:

location / {
        # 设置请求头的host 给Host设置$host(当前请求的host的值 )
        proxy_set_header Host $host;
        proxy_pass  http://gulimall;
    }

测试:

image-20220507190019433

梳理一下流程

我们通过在本机的host文件中进行了域名映射,

192.168.1.115 gulimall.com

所以当我们在浏览器中输入gulimall.com的时候,由于我们在本机配置了域名的映射,所以它会访问到我们映射的192.168.1.115这个IP地址。

为了实现我们在浏览器中输入gulimall.com

image-20220507202742609

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值