分布式电商项目 谷粒商城 学习笔记<3>

十、ES

7.进阶–聚合

聚合提供了从数据中分组和提取数据的能力。

最简单的聚合方法大致等于SQL Group by(分组统计)和SQL聚合函数(求平均 求最大 求最小)

聚合

是对查询出的数据做一些处理

# 分别为包含mill、平均年龄、
GET bank/_search
{
    
    
  "query": {
    
     # 查询出包含mill的
    "match": {
    
    
      "address": "Mill"
    }
  },
  "aggs": {
    
     #基于查询聚合
    "ageAgg": {
    
      # 聚合的名字,随便起
      "terms": {
    
     # 看值的可能性分布 就是分组统计 类似于group by
        "field": "age",
        "size": 10
      }
    },
    "ageAvg": {
    
     
      "avg": {
    
     # 看age值的平均
        "field": "age"
      }
    },
    "balanceAvg": {
    
    
      "avg": {
    
     # 看balance的平均
        "field": "balance"
      }
    }
  },
  "size": 0  # 不看详情
}

子聚合

也就是在aggs里再写一个aggs

GET bank/_search
{
    
    
  "query": {
    
    
    "match_all": {
    
    }
  },
  "aggs": {
    
    
    "ageAgg": {
    
    
      "terms": {
    
     # 看分布 对年龄分组
        "field": "age",
        "size": 100
      },
      "aggs": {
    
     # 与terms并列
        "ageAvg": {
    
     #平均  对已根据年龄分组的数据 进行求平均 比如 求20岁所有人的平均薪资
          "avg": {
    
    
            "field": "balance"
          }
        }
      }
    }
  },
  "size": 0
}

8.Mapping字段映射

是直接定义在索引下的,因为不同类型下、同名文档的处理方式是没有区别的。所以使用mapping映射,相当于屏蔽了类型,把文档直接放在了索引的下一级。

ElasticSearch7-去掉type概念

创建索引并指定映射

PUT /my_index  #相当于mysql创建一个表  指定各个字段的类型
{
    
    
  "mappings": {
    
    
    "properties": {
    
    
      "age": {
    
    
        "type": "integer"
      },
      "email": {
    
    
        "type": "keyword" # 指定为keyword
      },
      "name": {
    
    
        "type": "text" # 全文检索。保存时候分词,检索时候进行分词匹配
      }
    }
  }
}


PUT /my_index/_mapping  #相当于往表里填数据
{
    
    
  "properties": {
    
    
    "employee-id": {
    
    
      "type": "keyword",
      "index": false # 字段不能被检索。检索  表明新增的字段不能被检索,只是一个冗余字段。不能更新映射
对于已经存在的字段映射,我们不能更新。更新必须创建新的索引,进行数据迁移。
    }
  }
}



GET /my_index #查看映射

不能更新映射

对于已经存在的字段映射,我们不能更新。更新必须创建新的索引,进行数据迁移。

相当于不能 更改表的属性 (类比于mysql)

必须重新新建一个索引,然后把旧数据迁移过来。

创建新索引

PUT /newbank
{
    
    
  "mappings": {
    
    
    "properties": {
    
    
      "account_number": {
    
    
        "type": "long"
      },
      "address": {
    
    
        "type": "text"
      },
      "age": {
    
    
        "type": "integer"
      },
      "balance": {
    
    
        "type": "long"
      },
      "city": {
    
    
        "type": "keyword"
      },
      "email": {
    
    
        "type": "keyword"
      },
      "employer": {
    
    
        "type": "keyword"
      },
      "firstname": {
    
    
        "type": "text"
      },
      "gender": {
    
    
        "type": "keyword"
      },
      "lastname": {
    
    
        "type": "text",
        "fields": {
    
    
          "keyword": {
    
    
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "state": {
    
    
        "type": "keyword"
      }
    }
  }
}

将bank中的数据迁移到newbank中

POST _reindex
{
    
    
  "source": {
    
    
    "index": "bank",
    "type": "account" #原索引的名称和类型
  },
  "dest": {
    
    
    "index": "newbank"  #新索引的名称
  }
}

新索引的type会变为_doc (默认的索引类型 ,旧索引是account)

9.分词

一个tokenizer(分词器)接收一个字符流,将之分割为独立的tokens(词元,通常是独立的单词),然后输出tokens流。

POST _analyze
{
    
    
  "analyzer": "standard",
  "text": "The 2 Brown-Foxes bone."
}

会按单词分开,但是 对于中文,就不合适,因为它会把每个字都当成一个词 去分

所以我们需要使用其他分词器

安装ik分词器

在前面安装的elasticsearch时,我们已经将elasticsearch容器的“/usr/share/elasticsearch/plugins”目录,映射到宿主机的“ /mydata/elasticsearch/plugins”目录下,所以比较方便的做法就是下载“/elasticsearch-analysis-ik-7.4.2.zip”文件,然后解压到该文件夹下即可。安装完毕后,需要重启elasticsearch容器。

就是下载然后解压 然后放到/mydata/elasticsearch/plugins目录下 然后重启容器。

GET _analyze
{
    
    
   "analyzer": "ik_smart", 
   "text":"我是中国人"
}

GET _analyze
{
    
    
   "analyzer": "ik_max_word", 
   "text":"我是中国人"
}

补充:linux命令行编辑

vi 文件名

i 进入插入模式

esc退出插入模式

:wq退出并保存

自定义词库

修改/usr/share/elasticsearch/plugins/ik/config中的IKAnalyzer.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
	<comment>IK Analyzer 扩展配置</comment>
	<!--用户可以在这里配置自己的扩展字典 -->
	<entry key="ext_dict"></entry>
	 <!--用户可以在这里配置自己的扩展停止词字典-->
	<entry key="ext_stopwords"></entry>
	<!--用户可以在这里配置远程扩展字典 -->
	<entry key="remote_ext_dict">http://192.168.56.10/es/fenci.txt</entry>  #在这里配置自定义分词文件的路径
	<!--用户可以在这里配置远程扩展停止词字典-->
	<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

具体可以看笔记,这里就不深究了

https://blog.csdn.net/hancoder/article/details/113922398

10.elasticsearch-Rest-Client

导入依赖

<dependency>    <groupId>org.elasticsearch.client</groupId>    <artifactId>elasticsearch-rest-high-level-client</artifactId>    <version>7.4.2</version></dependency>

由于 springboot已经整合了ES 版本为6.8.5 所以要把spring-boot-dependencies中所依赖的ES版本改掉

<properties>
    <java.version>1.8</java.version>
    <elasticsearch.version>7.4.2</elasticsearch.version> #这里原来是6.8.5
</properties>

不需要数据源的微服务 依赖的父工程中有数据源相关配置处理

启动类加注解

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

配置类

@Configuration
public class GulimallElasticSearchConfig {
    
    

    public static final RequestOptions COMMON_OPTIONS;

    static {
    
    
        RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();

        COMMON_OPTIONS = builder.build();
    }

    @Bean
    public RestHighLevelClient esRestClient() {
    
    

        RestClientBuilder builder = null;
        // 可以指定多个es
        builder = RestClient.builder(new HttpHost(host, 9200, "http"));

        RestHighLevelClient client = new RestHighLevelClient(builder);
        return client;
    }
}

测试类

保存/修改

@Testpublic void indexData() throws IOException {
    
            // 设置索引    IndexRequest indexRequest = new IndexRequest ("users");    indexRequest.id("1");    User user = new User();    user.setUserName("张三");    user.setAge(20);    user.setGender("男");    String jsonString = JSON.toJSONString(user);        //设置要保存的内容,指定数据和类型    indexRequest.source(jsonString, XContentType.JSON);        //执行创建索引和保存数据    IndexResponse index = client.index(indexRequest, GulimallElasticSearchConfig.COMMON_OPTIONS);    System.out.println(index);}

保存语句再次发送就会变成修改操作。

检索及聚合

	@Test    public void find() throws IOException {
    
            // 1 创建检索请求        SearchRequest searchRequest = new SearchRequest();        searchRequest.indices("bank");  //填充索引        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();        // 构造检索条件//        sourceBuilder.query();//        sourceBuilder.from();//        sourceBuilder.size();//        sourceBuilder.aggregation();        sourceBuilder.query(QueryBuilders.matchQuery("address","mill")); //查询address包含mill的        System.out.println(sourceBuilder.toString());  //sourceBuilder就是一个查询语句的json串 //任何的查询条件 match matchall agg  都用各自的构造器构造好了放到SearchSourceBuilder中,然后塞入searchRequest                //构建第一个聚合条件:按照年龄的值分布          TermsAggregationBuilder agg1 = AggregationBuilders.terms("agg1").field("age").size(10);// 聚合名称		// 参数为AggregationBuilder        sourceBuilder.aggregation(agg1);        // 构建第二个聚合条件:平均薪资        AvgAggregationBuilder agg2 = AggregationBuilders.avg("agg2").field("balance");        sourceBuilder.aggregation(agg2);                        searchRequest.source(sourceBuilder);        // 2 执行检索        SearchResponse response = client.search(searchRequest, GulimallElasticSearchConfig.COMMON_OPTIONS);        // 3 分析响应结果        System.out.println(response.toString());  //response也是一个结果json串                        // 3.1 获取java bean        SearchHits hits = response.getHits();        SearchHit[] hits1 = hits.getHits();        for (SearchHit hit : hits1) {            hit.getId();            hit.getIndex();            String sourceAsString = hit.getSourceAsString(); //真正的查询结果在source中,获取到source,用json转换工具转成bean对象 这个bean需要自己创建VO类(或者已有的PO)            Account account = JSON.parseObject(sourceAsString, Account.class);            System.out.println(account);        }                // 3.2 获取聚合的结果        Aggregations aggregations = response.getAggregations();        Terms agg21 = aggregations.get("agg2");  //根据聚合名称获取        for (Terms.Bucket bucket : agg21.getBuckets()) {            String keyAsString = bucket.getKeyAsString();            System.out.println(keyAsString);        }    }

一般一个类名加s 代表这个类的构造器

十一、安装nginx

nginx可以理解为tomcat 是一个web服务器

随便启动一个nginx实例,只是为了复制出配置

docker run -p80:80 --name nginx -d nginx:1.10  

将容器内的配置文件拷贝到/mydata/nginx/conf/ 下

mkdir -p /mydata/nginx/htmlmkdir -p /mydata/nginx/logsmkdir -p /mydata/nginx/confdocker container cp nginx:/etc/nginx/*  /mydata/nginx/conf/ #由于拷贝完成后会在config中存在一个nginx文件夹,所以需要将它的内容移动到conf中mv /mydata/nginx/conf/nginx/* /mydata/nginx/conf/rm -rf /mydata/nginx/conf/nginx

终止原容器:

docker stop nginx

执行命令删除原容器:

docker rm nginx

创建新的Nginx,执行以下命令

docker run -p 80:80 --name nginx \ -v /mydata/nginx/html:/usr/share/nginx/html \ -v /mydata/nginx/logs:/var/log/nginx \ -v /mydata/nginx/conf/:/etc/nginx \ -d nginx:1.10

设置开机启动nginx

docker update nginx --restart=always

创建“/mydata/nginx/html/index.html”文件,测试是否能够正常访问

echo '<h2>hello nginx!</h2>' >index.html

访问:http://nginx所在主机的IP:80/index.html

十二、product-es准备

ES在内存中,所以在检索中优于mysql。ES也支持集群,数据分片存储。

1.确定索引模型

两种方案

一是按照spu查,也就是检索条件是spu,sku只存一个sku的id,这种方式很省空间。但是,有一个致命问题,就是当检索到一个符合条件的spu时,会一次性返回大量的skuid,这样在高并发环境下可能会造成阻塞。

二是按照sku存,也就是检索条件是sku,所有的sku信息都存,这种方式由于很多sku的spu属性是一样的,所以会有很多冗余字段。但是这种方式,虽然和第一种方式比起来占用的空间更多,但是每次查询返回的数据量比较少。

综合考虑,依照“空间换时间”的理念,选取第二种方案。

索引模型如下:

PUT product
{
    
    
    "mappings":{
    
    
        "properties": {
    
    
            "skuId":{
    
     "type": "long" },
            "spuId":{
    
     "type": "keyword" },  # 不可分词
            "skuTitle": {
    
    
                "type": "text",
                "analyzer": "ik_smart"  # 中文分词器
            },
            "skuPrice": {
    
     "type": "keyword" },  # 保证精度问题
            "skuImg"  : {
    
     
        			"type": "keyword""index": false,    # 不可被检索,不生成index
    		},  # 视频中有false
            "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" 
                "index": false,  # 不可被检索,不生成index
            }, # 视频里有false
            "attrs": {
    
    
                "type": "nested",
                "properties": {
    
    
                    "attrId": {
    
    "type": "long"  },
                    "attrName": {
    
    
                        "type": "keyword",
                        "index": false,
                        "doc_values": false
                    },
                    "attrValue": {
    
    "type": "keyword" }
                }
            }
        }
    }
}

2.nested嵌入式对象

属性是"type": “nested”,因为是内部的属性进行检索

数组类型的对象会被扁平化处理(对象的每个属性会分别存储到一起)

user.name=["aaa","bbb"]
user.addr=["ccc","ddd"]

这种存储方式,可能会发生如下错误:
错误检索到{aaa,ddd},这个组合是不存在的

数组的扁平化处理会使检索能检索到本身不存在的,为了解决这个问题,就采用了嵌入式属性,数组里是对象时用嵌入式属性(不是对象无需用嵌入式属性)

十三、商品上架

1.基本思路

后台管理系统把spuid传到后端,后端根据spuid从mysql数据库查出spuid对应的一系列sku,然后把这些sku上传到es。当然这中间涉及到PO类与ESModel的转换。

2.批量查询sku是否有库存

// sku的规格参数相同,因此我们要将查询规格参数提前,只查询一次/*** 查询sku是否有库存* 返回skuId 和 stock库存量*/@PostMapping("/hasStock")public R getSkuHasStock(@RequestBody List<Long> SkuIds){    List<SkuHasStockVo> vos = wareSkuService.getSkuHasStock(SkuIds);    return R.ok().setData(vos);}

3.给一个skuEsModels 批量上传ES

/**
	 * 上架商品
	 */
@PostMapping("/product") // ElasticSaveController
public R productStatusUp(@RequestBody List<SkuEsModel> skuEsModels){
    
    

    boolean status;
    try {
    
    
        status = productSaveService.productStatusUp(skuEsModels);
    } catch (IOException e) {
    
    
        log.error("ElasticSaveController商品上架错误: {}", e);
        return R.error(BizCodeEnum.PRODUCT_UP_EXCEPTION.getCode(), BizCodeEnum.PRODUCT_UP_EXCEPTION.getMsg());
    }
    if(!status){
    
    
        return R.ok();
    }
    return R.error(BizCodeEnum.PRODUCT_UP_EXCEPTION.getCode(), BizCodeEnum.PRODUCT_UP_EXCEPTION.getMsg());
}


public boolean productStatusUp(List<SkuEsModel> skuEsModels) throws IOException {
    
    
    // 1.给ES建立一个索引 product
    BulkRequest bulkRequest = new BulkRequest();
    // 2.构造保存请求
    for (SkuEsModel esModel : skuEsModels) {
    
    
        // 设置索引
        IndexRequest indexRequest = new IndexRequest(EsConstant.PRODUCT_INDEX);
        // 设置索引id
        indexRequest.id(esModel.getSkuId().toString());
        String jsonString = JSON.toJSONString(esModel);
        indexRequest.source(jsonString, XContentType.JSON);
        // add
        bulkRequest.add(indexRequest);
    }
    // bulk批量保存
    BulkResponse bulk = client.bulk(bulkRequest, GuliESConfig.COMMON_OPTIONS);
    // TODO 是否拥有错误
    boolean hasFailures = bulk.hasFailures();
    if(hasFailures){
    
    
        List<String> collect = Arrays.stream(bulk.getItems()).map(item -> item.getId()).collect(Collectors.toList());
        log.error("商品上架错误:{}",collect);
    }
    return hasFailures;
}

4.根据spuId封装上架数据

也就是根据spuid封装ESModels

// SpuInfoServiceImpl 
public void upSpuForSearch(Long spuId) {
    
    
        //1、查出当前spuId对应的所有sku信息,品牌的名字
        List<SkuInfoEntity> skuInfoEntities=skuInfoService.getSkusBySpuId(spuId);
        //TODO 4、根据spu查出当前sku的所有可以被用来检索的规格属性
        List<ProductAttrValueEntity> productAttrValueEntities = productAttrValueService.list(new QueryWrapper<ProductAttrValueEntity>().eq("spu_id", spuId));
        List<Long> attrIds = productAttrValueEntities.stream().map(attr -> {
    
    
            return attr.getAttrId();
        }).collect(Collectors.toList());
        List<Long> searchIds=attrService.selectSearchAttrIds(attrIds); #这里是根据id查询数据库 下面有sql语句
        Set<Long> ids = new HashSet<>(searchIds);
        List<SkuEsModel.Attr> searchAttrs = productAttrValueEntities.stream().filter(entity -> {
    
    
            return ids.contains(entity.getAttrId());
        }).map(entity -> {
    
    
            SkuEsModel.Attr attr = new SkuEsModel.Attr();
            BeanUtils.copyProperties(entity, attr);
            return attr;
        }).collect(Collectors.toList());


        //TODO 1、发送远程调用,库存系统查询是否有库存
        Map<Long, Boolean> stockMap = null;
        try {
    
    
            List<Long> longList = skuInfoEntities.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());
            List<SkuHasStockVo> skuHasStocks = wareFeignService.getSkuHasStocks(longList);
            stockMap = skuHasStocks.stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, SkuHasStockVo::getHasStock));
        }catch (Exception e){
    
    
            log.error("远程调用库存服务失败,原因{}",e);
        }

        //2、封装每个sku的信息
        Map<Long, Boolean> finalStockMap = stockMap;
        List<SkuEsModel> skuEsModels = skuInfoEntities.stream().map(sku -> {
    
    
            SkuEsModel skuEsModel = new SkuEsModel();
            BeanUtils.copyProperties(sku, skuEsModel);
            skuEsModel.setSkuPrice(sku.getPrice());
            skuEsModel.setSkuImg(sku.getSkuDefaultImg());
            //TODO 2、热度评分。0
            skuEsModel.setHotScore(0L);
            //TODO 3、查询品牌和分类的名字信息
            BrandEntity brandEntity = brandService.getById(sku.getBrandId());
            skuEsModel.setBrandName(brandEntity.getName());
            skuEsModel.setBrandImg(brandEntity.getLogo());
            CategoryEntity categoryEntity = categoryService.getById(sku.getCatalogId());
            skuEsModel.setCatalogName(categoryEntity.getName());
            //设置可搜索属性
            skuEsModel.setAttrs(searchAttrs);
            //设置是否有库存
            skuEsModel.setHasStock(finalStockMap==null?false:finalStockMap.get(sku.getSkuId()));
            return skuEsModel;
        }).collect(Collectors.toList());

    
        //TODO 5、将数据发给es进行保存:gulimall-search
        R r = searchFeignService.saveProductAsIndices(skuEsModels);
        if (r.getCode()==0){
    
    
            this.baseMapper.upSpuStatus(spuId, ProductConstant.ProductStatusEnum.SPU_UP.getCode());
        }else {
    
    
            log.error("商品远程es保存失败");
        }
    }

selectSearchAttrIds 对应的持久层sql

<resultMap type="com.atguigu.gulimal1.product.entity.AttrEntity" id="attrMap">
		<result property="attrId" column="attr_id" />
		<result property="attrName" column="attr_name" />
		<result property="searchType" column="search_type" />
		<result property="valueType" column="value_type" />
		<result property="icon" column="icon" / >
		<result property="valueSelect" column="value_select" />
		<result property="attrType" column="attr_type" />
		<result property="enab1e" column= "enable"/>
		<result property="catelogId" column="catelog_id" />
		<result property="showDesc" column="show_dese" />
< / resu1tMap>
<!-- 
	resultMap 对应的返回结果PO与数据库列名的映射
	Long与long相比,可以处理null的情况
-->
<select id="selectSearchAttrIds" resu1tType="java.lang.Long">
		SELECT attr_id FROM ‘pms_attr’ WHERE attr_id IN
		<foreach collection="attrIds" item="id" separator=" , " open="(" close=")">
			#{id}
		< / foreach>
		AND search_type = 1
</ select>
		
<!--
    此处attrIds是一个集合,可以在xml中用foreach来遍历。  open close 就是开始和结束处要添加的符号  因为前面是IN,所以要添加	的是两个括号  separator 是每个元素之间的分隔符
-->

根据spu查出所有sku的信息,然后判断是否有库存,根据是否有库存,写bool类型hasStock(ESModel和PO的差别)

,的封装ESModels、调用 3 的服务 上传

5.一个小高端的写法

当要对一个集合中的元素做相同处理时

可以这样

 List<CategoryEntity> newCategoryEntities = categoryEntities.stream().filter(
                categoryEntity ->
                    categoryEntity.getEntityNum() == 1
        ).map(categoryEntity -> {
    
    
            categoryEntity.setSize(new Long(100));
            return categoryEntity;
        }).collect(Collectors.toList());

集合总的元素都可以用lmbda表达式操作,操作完再收集成一个集合。

十四、Nginx

1.简述

正向代理 就是我要访问谷歌,访问不了,然后我请另一台服务器帮我转到谷歌,那么就称这台服务器正向代理了我的请求。

反向代理,就是我要访问谷歌,谷歌把我转到了百度,那么就称谷歌反向代理了我的请求。(我并没有要去百度)

2.Nginx+网关的逻辑

Nginx其实就是为了屏蔽内网的ip,对外只暴露一个Nginx的ip。之后有了域名后,域名映射的地址就是Nginx的地址。

要实现的逻辑:本机浏览器请求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),这样就得到了响应

3.Nginx配置文件解析

nginx.conf:

全局块:配置影响nginx全局的指令。如:用户组,nginx进程pid存放路径,日志存放路径,配置文件引入,允许生成worker process故障等
events块:配置影响 Nginx 服务器与用户的网络连接,常用的设置包括是否开启对多 work process下的网络连接进行序列化,是否允许同时接收多个网络连接,选取哪种事件驱动模型来处理连接请求,每个 word process 可以同时支持的最大连接数等。
http块:
http全局块:配置的指令包括文件引入、MIME-TYPE 定义、日志自定义、连接超时时间、单链接请求数上限等。错误页面等
server块:这块和虚拟主机有密切关系,虚拟主机从用户角度看,和一台独立的硬件主机是完全一样的。每个 http 块可以包括多个 server 块,而每个 server 块就相当于一个虚拟主机。
location1:配置请求的路由,以及各种页面的处理情况
location2

4.Nginx+网关配置

修改主机hosts,映射gulimall.com到192.168.56.10。关闭防火墙

此时本机访问gulimall.com 就可以请求到nginx的首页index.html了

要让nginx反向代理到本机的10000端口,主要需要修改server配置

server {
    
    listen     80; server_name  gulimall.com ; #charset koi8-r;#access_log/var/log/nginx/log/host.access.logmain;location / {proxy_pass http:/ /192.168.56.1: 10000}

listen 是监听的端口号,server_name是监听的域名 。因为做了映射,所以gulimall.com其实是主机的ip

location就是要转发的ip+端口

修改nginx/conf/nginx.conf,将upstream映射到我们的网关服务

upstream gulimall{
    
            # 88是网关        server 192.168.56.1:88;    }

修改nginx/conf/conf.d/gulimall.conf,接收到gulimall.com的访问后,如果是/,转交给指定的upstream,由于nginx的转发会丢失host头,造成网关不知道原host,所以我们添加头信息

location / {
    
            proxy_pass http://gulimall;        proxy_set_header Host $host;    }

网关路由转发配置

配置gateway为服务器,将域名为**.gulimall.com转发至商品服务。配置的时候注意 网关优先匹配的原则,所以要把这个配置放到后面

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

总之一句,nginx就是类似网关的作用,主要是为了隐藏主机的域名。外界的请求请求域名,而域名映射的是nginx的地址,然后nginx再把用户的请求转发到真实的服务器。

猜你喜欢

转载自blog.csdn.net/GBS20200720/article/details/121188998