全栈从入门到精通(二)

十二、分布式基础篇总结        
101、分布式基础篇总结
【1】分布式基础篇开发结束
【2】微服务:服务独立自治,依赖nacos
注册中心、配置中心nacos;
远程调用Feign  来实现的,springboot简单来说就是使用Feign给对方服务发起个请求
网关:所有请求都是通过网关代理的,这样端口变化时,只要服务名称不变,也不影响请求。
**********************************************************************************************
【3】基础开发
springboot、springcloud、mybatisPlus、Vue组件化、阿里云对象存储
【4】开发环境
Linux、Docker、MySQL、Redis、逆向工程、Vbox
【5】开发规范
JSR303、全局异常处理、全局统一返回Res、全局跨域处理
枚举、业务状态码、VO/TO/PO、逻辑删除
Lombok:@Data、@Slf4j

****************************************************************************************************************************************************************************

13、全文检索ES
102、全文检索ES概述
【1】分布式的开源的搜索和分析引擎。适用于所有的数据类型。
【2】作用:
应用程序搜索
网站搜索
企业搜索
日志处理分析
基础指标和容器监测
应用程序性能监测
地理空间数据分析和可视化
安全分析
业务分析
【3】底层是开源库Lucene,ES是Lucene的封装,提供了REST API的操作接口,开箱即用。
天然的跨平台,https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
【4】基本概念
Index 索引---相当于mysql的insert(动词) 或database(名词)!!!!!存数据
******************************************************************************************
Type 类型---可以定义一个或多个---相当于mysql的Table,每一种类型的数据放在一起
******************************************************************************************
Document 文档 ---JSON格式的,类似于mysql存储的一条条数据!!!!JSON格式
******************************************************************************************
有个类比图,手机存储了,注意查看!!!!!!!!!!!!!
【5】倒排索引
分词:将整句拆分为单词。
查询相关记录:但是会根据搜索词,给相关记录进行打分,按照得分高-低排序
******************************************************************************************
103、Docker安装ES
【1】下载镜像文件
docker pull elasticsearch:7.4.2
docker pull kibana:7.4.2  # 可视化操作界面
删除历史镜像:
docker rmi -f xxx
******************************************************************************************
mkdir -p /mydata/elasticsearch/config
mkdir -p /mydata/elasticsearch/data
echo "http.host: 0.0.0.0" >> /mydata/elasticsearch/config/elasticsearch.yml
chmod -R 777 /mydata/elasticsearch/ 保证权限!!!!!!!!!!!!!!!!!!!!!

docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
-e "discovery.type=single-node" \-e ES_JAVA_OPTS="-Xms64m -Xmx512m" \
-v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
-v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.4.2
******************************************************************************************
docker ps
访问 http://192.168.0.205:9200/
104、安装Kibana
【1】可以用postman测试API
http://192.168.0.205:9200/_cat/nodes
【2】Kibana的安装
!!!!!!!!!!!!!注意改成自己的虚拟机地址
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.0.205:9200 -p 5601:5601 \
-d kibana:7.4.2
******************************************************************************************
docker logs 容器id开头就行,可以查看容器启动日志!!!!!!!!!!!!!!!!
******************************************************************************************
105、ES入门_cat  0分钟
【1】清理下k8s docker环境,需要先停止systemctl stop kubelet
然后清理容器
最后清理镜像
三步走
【2】设置docker镜像自启动
docker update --restart=always $(docker ps -q)
【3】_cat查询es的一些信息
http://192.168.0.205:9200/_cat/health
返回
1689599441 13:10:41 elasticsearch green 1 1 3 3 0 0 0 0 - 100.0%
【4】查看主节点
http://192.168.0.205:9200/_cat/master
Ayr5G9stTXSavwWJUAIl2A 127.0.0.1 127.0.0.1 af18168c5811(容器id)
******************************************************************************************
【5】查看数据库(索引)
http://192.168.0.205:9200/_cat/indices
green open .kibana_task_manager_1   becRqzRQTHSr4rKjbcfXMg 1 0 2 1 24.6kb 24.6kb
green open .apm-agent-configuration 6ajqdfpOSjG8JwinmdUGMA 1 0 0 0   283b   283b
green open .kibana_1                puqeYEQZQY6avlMIS7Q5UQ 1 0 8 0   32kb   32kb
******************************************************************************************
106、put与post新增数据
【1】保存在那个索引的哪个类型下(就是mysql的那个数据库,那个表)
http://192.168.0.205:9200/customer/external/1   postman发起put请求!!!!
{ 
"name": "John Doe"
}
返回:
{
    "_index": "customer", // 元数据
    "_type": "external",
    "_id": "1",
    "_version": 1, // 不断叠加
    "result": "created", // 发送多次是更新
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 0,
    "_primary_term": 1
}
******************************************************************************************
【2】put需要带id,而post不需要
******************************************************************************************
107、get查询数据&乐观锁字段
【1】查询数据
http://192.168.0.205:9200/customer/external/1   GET请求了
返回:
{
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 4,
    "_seq_no": 3,
    "_primary_term": 1,
    "found": true,
    "_source": {
        "name": "John Doe"
    }
}
******************************************************************************************
【2】模拟并发修改
更新携带 ?if_seq_no=3&if_primary_term=1
这样就只能改一次。查+改,规范操作修改
******************************************************************************************
108、更新文档再说明:
【1】post带update会自动对比数据,与原来一样就会犯noop说明都不做
http://192.168.0.205:9200/customer/external/1/_update

http://192.168.0.205:9200/customer/external/1 不带update doc就不会比对
******************************************************************************************
【2】put和post不检查一样
注意要写成doc语法
******************************************************************************************
109、delete 删除文档
【1】http://192.168.0.205:9200/customer/external/1  DELETE请求
{
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 9,
    "result": "deleted",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 8,
    "_primary_term": 1
}
【2】查询数据http://192.168.0.205:9200/customer/external/1 GET
{
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "found": false
}
【3】http://192.168.0.205:9200/customer/  DELETE请求
{
    "acknowledged": true
}
【4】查询 http://192.168.0.205:9200/customer/external/1 GET
{
    "error": {
        "root_cause": [
            {
                "type": "index_not_found_exception",
                "reason": "no such index [customer]",
                "resource.type": "index_expression",
                "resource.id": "customer",
                "index_uuid": "_na_",
                "index": "customer"
            }
        ],
        "type": "index_not_found_exception",
        "reason": "no such index [customer]",
        "resource.type": "index_expression",
        "resource.id": "customer",
        "index_uuid": "_na_",
        "index": "customer"
    },
    "status": 404
}
【5】批量API
http://192.168.0.205:9200/customer/external/_bulk POST  类型TEXT
要用kibana测试
http://192.168.0.205:5601/app/kibana#/dev_tools/console?_g=()
POST /customer/external/_bulk
{"index":{"_id":"1"}}
{"name": "John Doe" }
{"index":{"_id":"2"}}
{"name": "Jane Doe" }
点下运行按钮
******************************************************************************************
POST /_bulk
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title": "My first blog post" }
{ "index": { "_index": "website", "_type": "blog" }}
{ "title": "My second blog post" }
{ "update": { "_index": "website", "_type": "blog", "_id": "123"} }
{ "doc" : {"title" : "My updated blog post"} }
******************************************************************************************
POST bank/account/_bulk
https://raw.githubusercontent.com/elastic/elasticsearch/7.4/docs/src/test/resources/accounts.json
******************************************************************************************
110、ES两种查询方式,高级用法
【1】设置es与kibana自启动
docker update af1 --restart=always (es 容器id前三位)
docker update a22 --restart=always(kibana 容器id前三位)
重启看下是否自启动了,搞定了!!!!!!!!!!!!!!!!!!!!!!
******************************************************************************************
【2】GET bank/_search?q=*&sort=account_number:asc
【3】另一种查询方式
GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "account_number": {
        "order": "desc"
      }
    }
  ]
}
******************************************************************************************
111、全文检索 ES  QueryDSL基本使用与match_all
【1】查询存款高-低
GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "from": 0,
  "size": 5,
  "sort": [
    {
      "balance": {
        "order": "desc"
      }
    }
  ]
}
【2】_source 指定返回字段
GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "from": 0,
  "size": 5,
  "_source": ["balance","age"], 
  "sort": [
    {
      "balance": {
        "order": "desc"
      }
    }
  ]
}
******************************************************************************************
112、match查询
【1】全文检索
GET bank/_search
{
  "query": {
    "match": {
      "address": "kings"
    }
  }
}
******************************************************************************************
113、ES全文检索-match_phrase 短语匹配
【1】包含完整的短语,才会返回结果
GET bank/_search
{
  "query": {
    "match_phrase": {
      "address": "mill road"
    }
  }
}
******************************************************************************************
114、multi_match多字段匹配
【1】多个字段或包含查询字段就可以
GET bank/_search
{
  "query": {
    "multi_match": {
      "query": "mill",
      "fields": [
        "state",
        "address"
      ]
    }
  }
}
******************************************************************************************
115、bool 复合查询
【1】性别是女,并且地址里包含xxx
GET bank/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "address": "mill"
          }
        },
        {
          "match": {
            "gender": "M"
          }
        }
      ]
    }
  }
}
【2】性别是女,并且地址里“不”包含xxx
GET bank/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "address": "mill"
          }
        },
        {
          "match": {
            "gender": "M"
          }
        }
      ],
      "should": [
        {
          "match": {
            "address": "lane"
          }
        }
      ],
      "must_not": [
        {
          "match": {
            "email": "baluba.com"
          }
        }
      ]
    }
  }
}
******************************************************************************************
【3】应该should 满足不满足都行,满足的得分会更高
GET bank/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "address": "mill"
          }
        },
        {
          "match": {
            "gender": "M"
          }
        }
      ],
      "should": [
        {
          "match": {
            "address": "lane"
          }
        }
      ]
    }
  }
}
******************************************************************************************
116、filter【结果过滤】
【1】gte-lte 多少到多少之间:
GET bank/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "address": "mill"
          }
        }
      ],
      "filter": {
        "range": {
          "balance": {
            "gte": 10000,
            "lte": 20000
          }
        }
      }
    }
  }
}
【2】和must最大区别,filter不会贡献相关性得分。
******************************************************************************************
117、term
【1】精确数值字段可以用term,文本不要用
GET bank/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "age": {
              "value": "28"
            }
          }
        },
        {
          "match": {
            "address": "990 Mill Road"
          }
        }
      ]
    }
  }
}
【2】存储+检索+分析功能
******************************************************************************************
118、aggregations(执行聚合)
【1】等于mysql的group by ....count...
【2】查询年龄的分布情况
GET bank/_search
{
  "query": {
    "match": {
      "address": "mill"
    }
  },
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "age"
      }
    },
    "avg_age": {
      "avg": {
        "field": "age"
      }
    }
  },
  "size": 10
}
******************************************************************************************
【3】按年龄聚合,求平均工资
GET bank/account/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "age_avg": {
      "terms": {
        "field": "age",
        "size": 1000
      },
      "aggs": {
        "banlances_avg": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  },
  "size": 1000
}
******************************************************************************************
【4】分别统计男女平均薪资
GET bank/account/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "age_agg": {
      "terms": {
        "field": "age",
        "size": 100
      },
      "aggs": {
        "gender_agg": {
          "terms": {
            "field": "gender.keyword",
            "size": 100
          },
          "aggs": {
            "balance_avg": {
              "avg": {
                "field": "balance"
              }
            }
          }
        },
        "balance_avg": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  },
  "size": 1000
}
******************************************************************************************
119、Mapping 映射
【1】字段类型,什么类型存储,什么类型检索的
【2】7.0以后的版本就移出了类型
【3】GET bank/_mapping,能够看到每一个属性的影射类型
【4】影射规则的创建
PUT /my-index
{
  "mappings": {
    "properties": {
      "age": {
        "type": "integer"
      },
      "email": {
        "type": "keyword"
      },
      "name": {
        "type": "text"
      }
    }
  }
}
******************************************************************************************
{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "my-index"
}
******************************************************************************************
120、添加新的影射字段
【1】追加影射
PUT /my-index/_mapping
{
  "properties": {
    "employee-id": {
      "type": "keyword",
      "index": false // 不被检索
    }
  }
}
******************************************************************************************
121、更新映射
【1】对于已经存在的映射字段,我们不能更新。更新必须创建新的索引进行数据迁移
【2】只能通过数据迁移来更新影射
【3】想修改只能通过创建新的来修改
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"
      }
    }
  }
}
******************************************************************************************
GET /newbank/_mapping
【4】老数据迁移到新数据
POST _reindex
{
  "source":{
    "index":"bank",
    "type":"account"
  },
  "dest":{
    "index":"newbank"
  }
}

GET /newbank/_search
******************************************************************************************
122、分词
【1】一个 tokenizer(分词器)接收一个字符流,将之分割为独立的 tokens(词元,通常是独立
的单词),然后输出 tokens 流。
POST _analyze
{
  "analyzer": "standard",
  "text":"nice to meet you"
}
*******************************************************************************************
{
  "tokens" : [
    {
      "token" : "nice",
      "start_offset" : 0,
      "end_offset" : 4,
      "type" : "<ALPHANUM>",
      "position" : 0
    },
    {
      "token" : "to",
      "start_offset" : 5,
      "end_offset" : 7,
      "type" : "<ALPHANUM>",
      "position" : 1
    },
    {
      "token" : "meet",
      "start_offset" : 8,
      "end_offset" : 12,
      "type" : "<ALPHANUM>",
      "position" : 2
    },
    {
      "token" : "you",
      "start_offset" : 13,
      "end_offset" : 16,
      "type" : "<ALPHANUM>",
      "position" : 3
    }
  ]
}
【2】安装支持中文的分词器
cd /mydata/elasticsearch/plugins
去百度网盘下载,自己保存了
unzip elasticsearch-analysis-ik-7.4.2.zip  解压后把zip删了,记得卧槽!!!!!!!!!

chmod -R 777 ik/ 修改权限
docker exec -it af18 /bin/bash
elasticsearch-plugin list 看到ik即可

docker restart elasticsearch 重启下es
*******************************************************************************************
POST _analyze
{
  "analyzer": "ik_smart",
  "text": "我是中国人"
}
*******************************************************************************************
POST _analyze
{
  "analyzer": "ik_max_word",
  "text": "我是中国人"
}
*******************************************************************************************
123、修改linux网络设置,开启root权限
【1】解决ping baidu不通的问题
cd /etc/sysconfig/network-scripts/
GATEWAY=xxxx.0.1
DNS1=114.114.114.114
DNS2=8.8.8.8
service network restart
就解决了!!!!!!!!!!!!!!
*******************************************************************************************
【2】修改yum源头
备份原 yum 源
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
使用新 yum 源
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo
生成缓存
yum makecache
【3】配置后安装简直起飞呀
yum install -y wget
yum install -y unzip
*******************************************************************************************
124、自定义分词  0分钟
【1】又学会了一招,删除node_modules,然后npm install
【2】安装nginx
mkdir nginx
docker run -p 80:80 --name nginx -d nginx:1.10  #如果本地没有则自动下载
docker container cp nginx:/etc/nginx .  # 将容器的配置文件拷贝到当前目录
cd nginx/
ls
docker stop nginx
docker rm nginx
mv nginx conf
mkdir nginx
mv conf/ 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
*******************************************************************************************
http://192.168.0.205/
*******************************************************************************************
[root@192-168-0-205 html]# cd es
[root@192-168-0-205 es]# ls
[root@192-168-0-205 es]# vim fenci.txt
http://192.168.0.205/es/fenci.txt
*******************************************************************************************
<?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.0.205/es/fenci.txt</entry>
        <!--用户可以在这里配置远程扩展停止词字典-->
        <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
主要是配置地址
/mydata/elasticsearch/plugins/ik/config
*******************************************************************************************
docker restart elasticsearch
/mydata/nginx/html/es/fenci.txt
*******************************************************************************************
docker update elasticsearch --restart=always
docker update nginx --restart=always
设置docker容器自启动
125、JAVA操作ES
【1】通过9300:TCP 官方不建议使用
【2】9200操作ES
JestClient 非官方,更新慢
RestTemplate:ES需要自己封装,麻烦
HttpClient、okHttp同上
【4】最终我们使用RestClient
package com.gulimall.search.config;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class GulimallElasticSearchConfig {

    // @Bean
    // public RestHighLevelClient esRestClient(){
    //     RestHighLevelClient client = new RestHighLevelClient(
    //             RestClient.builder(new HttpHost("192.168.137.14", 9200, "http")));
    //     return  client;
    // }

    public static final RequestOptions COMMON_OPTIONS;

    static {
        RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
        // builder.addHeader("Authorization", "Bearer " + TOKEN);
        // builder.setHttpAsyncResponseConsumerFactory(
        //         new HttpAsyncResponseConsumerFactory
        //                 .HeapBufferedResponseConsumerFactory(30 * 1024 * 1024 * 1024));
        COMMON_OPTIONS = builder.build();
    }

    @Bean
    public RestHighLevelClient esRestClient() {
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("192.168.0.205", 9200, "http")));
        return client;
    }
}
*******************************************************************************************
126、测试整合
【1】干事情还是要有点耐心的
spring.application.name=search
spring.cloud.nacos.config.server-addr=192.168.0.205:1111
【2】nacos的配置真是耽误事
spring.cloud.nacos.discovery.server-addr=192.168.0.205:1111
spring.application.name=search
server.port=12000
spring.redis.host=192.168.0.205
spring.redis.port=6379
【3】测试方法
@SpringBootTest
@RunWith(SpringRunner.class)
public class GulimallSearchApplicationTests {
    @Resource
    private RestHighLevelClient restHighLevelClient;

    @Test
    public void indexData() throws Exception {
        IndexRequest indexRequest = new IndexRequest("users");
        indexRequest.id("1");
        User user = new User();
        String reqJson = JSON.toJSONString(user);
        indexRequest.source(reqJson, XContentType.JSON); // 要保存的内容
        // 执行操作
        restHighLevelClient.index(indexRequest, GulimallElasticSearchConfig.COMMON_OPTIONS);
    }
【4】通过后就可以查询了
@SpringBootTest
@RunWith(SpringRunner.class)
public class GulimallSearchApplicationTests {
    @Resource
    private RestHighLevelClient restHighLevelClient;

    @Test
    public void indexData() throws Exception {
        IndexRequest indexRequest = new IndexRequest("users");
        indexRequest.id("1");
        User user = new User();
        String reqJson = JSON.toJSONString(user);
        indexRequest.source(reqJson, XContentType.JSON); // 要保存的内容
        // 执行操作
        IndexResponse indexResponse = restHighLevelClient.index(indexRequest, GulimallElasticSearchConfig.COMMON_OPTIONS);
        System.out.println(indexResponse);
    }

    @Data
    class User {
        private String name = "zs";
        private String gender = "男";
        private Integer age = 18;
    }
	
GET users/_search
*******************************************************************************************
127、测试复杂检索
【1】有些事只需要懂思路,万事亲力亲为,不是长久之道,必须学会借力。
【2】借力要懂得借力,懂得维系,ES想学就抽时间学下,不想学就算了,Lucene
【3】searchData方法,有点类似mybatisplus的使用呢

****************************************************************************************************************************************************************************

14、商城上架
128、sku在es中存储模型分析
【1】es是存在内存中的
【2】各种维度的检索
129、nested数据类型
【1】es会对这个类型的数据扁平化处理,nested避免这类处理带来的问题
【2】整理代码累死人,这才是我学习的价值。为什么不用已有的?
因为自己的redis mysql nacos连接的都是本地的,怎么改????
不如自己边学边改,最后成为自己的项目了。
改代码的同时,自己也明白了一些代码细节和重点!!!!!!!!!!!!!!!!!!!!
【3】太复杂的逻辑就是反人类了!!!
131、构造sku检索属性
【1】调出id,调出检索的商品(search type是1)
132、远程查询库存的功能
【1】主要是远程查询库存
//TODO 1、发送远程调用,库存系统查询是否有库存
	Map<Long, Boolean> stockMap = null;
	try {
		R skuHasStock = wareFeignService.getSkuHasStock(skuIdList);
		//
		TypeReference<List<SkuHasStockVo>> typeReference = new TypeReference<List<SkuHasStockVo>>() {
		};
		stockMap = skuHasStock.getData(typeReference).stream()
				.collect(Collectors.toMap(SkuHasStockVo::getSkuId, item -> item.getHasStock()));
	} catch (Exception e) {
		log.error("库存服务查询异常:原因{}", e);
	}
133、远程上架接口
【1】看看别人的Contants是怎么写的
public class EsConstant {
    //在es中的索引
    public static final String PRODUCT_INDEX = "gulimall_product";
    public static final Integer PRODUCT_PAGESIZE = 16;
}
******************************************************************************************
134、上架接口调试&feign源码  0
【1】测试代码是否有问题
135、抽取响应结果&上架测试完成
【1】GulimallProductApplication终于在11111端口启动成功,皇天不负有心人
【2】最起码要学会各种配置,到时候项目用到了才能结合
【3】终止windows的端口占用
执行命令 netstat -ano|findstr "端口值",比如 netstat -ano|findstr  "10000"
打开“任务管理器”工具,找到对应的PID=7632,可以看到该端口占用的后台程序,结束任务即可。
******************************************************************************************
136、整合thymeleaf渲染首页
【1】nginx静态资源----网关---微服务
动静分离,静态就给nginx,动态的给微服务处理
【2】静态资源:图片、js、css
动态资源:服务处理的请求
【3】引入依赖
 <!-- 模板引擎 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
【4】资源复制后突然就好了,卧槽!!!!!!!!!!!!
【5】解释了很多的thymeleaf的源码,我不需要.........
137、整合dev-tools渲染一级分类数据
【1】就是移入展示对应的分类....
【2】devtools 热启动
138、渲染二级三级分类数据
【1】主要是数据类的获取
139、nginx搭建域名访问环境(反向代理配置) 0
【1】代理
帮我们上网,就是正向代理。
反向代理:屏蔽内网服务器信息,负载均衡访问
【2】DNS配置了域名解析信息
【3】本地可以指定域名,不用过DNS
【4】说白了就是修改hosts,卧槽!!!!!!!!!!!!
【5】Nginx配置说明
全局块
events 事假块
http块
include /etc/nginx/conf.d/*.conf;
*******************************************************************************
server块
【6】配置转到指定地址
listen 80;80端口
server_name  mall.com;  指定来源于哪个域名?
proxy_pass http://192.168.0.105:10000  指定代理访问的IP
docker restart nginx
docker logs nginx  查看启动失败的原因
proxy_pass http://192.168.0.105:10000; 少了分号
docker ps查看启动情况
【7】流程总结mall.com:10000
192.168.0.205       mall.com--->首先域名指向虚拟机--->符合域名是mall.com:80端口--->
就回调用proxy_pass找IP--->又找到了192.168.0.105本机的IP
*******************************************************************************
【8】但是服务很多,不能一个个配置,所以要配置代理网关
140、搭建域名访问环境
【1】指向网关
【2】上有服务器
upstream mall{
      server 192.168.0.105:88;
	  // 可以配置多个网关
    }
【3】这个mall是根据upsream mall的名字来取的
location / {
        proxy_pass http://mall;
    }
【4】再访问就可以到网关了
配置网关的路路由规则!!!!!!!!!!!!!!!!!!!!!!!!!!!
# mall_host
spring.cloud.gateway.routes[7].id=host_route
spring.cloud.gateway.routes[7].uri=lb://product
spring.cloud.gateway.routes[7].predicates[0]=Host=**.mall.com,mall.com
【5】但是报错了404,为什么呢?
应为nginx,会丢失Host信息,所以需要配置不丢失!!!!!
location / {
        proxy_set_header Host $host;
        proxy_pass http://mall;
    }
【6】大招配置
ai,设置后就可以访问成功了,mall.com
192.168.0.205       mall.com--->首先域名指向虚拟机--->符合域名是mall.com:80端口--->
就回调用proxy_pass找IP--->又找到了192.168.0.105本机的IP--->到网关88端口--->
根据 proxy_set_header Host $host;设置的域名,网关又转发到product,访问首页。
所有mall.com 就能直接访问,连mall.com:10000都不用了
【7】域名映射效果
请求接口:mall.com
页面也是:mall.com
nginx直接代理给网关,网关判断
如果是/api/*****,转交给对应的服务器
如果是满足域名映射,转交给对应的服务

****************************************************************************************************************************************************************************

15、性能压测
141、压力测试-基本概述
【1】是为了考察当前软硬件环境下系统所能承受的最大负荷并帮助找到系统瓶颈所在。
【2】压测能发现更多的两种错误:内存泄露、并发与同步
QPS每秒的查询数
【3】最大响应时间
【4】最小响应时间
【5】90%的响应时间
【6】吞吐量、响应时间、错误率
【7】测试工具,JMeter
******************************************************************************************
142、ApacheJMeter
【1】JMeter的下载安装
【2】测试计划-线程组200  循环100次
【3】测试百度
【4】测试自己的首页
******************************************************************************************
143、JMeter在windows下地址占用bug解决
【1】让我重新熟悉了环境,emmm
【2】但是新版修复了这个问题....搞笑了呀
******************************************************************************************
144、性能监控-堆内存与垃圾回收
【1】是CPU密集型还是IO密集型
【2】堆
基于C—>JVM—>JAVA
【3】Heap堆区
【4】新生代 伊甸园区、幸存者区域
【5】老年代,在新生代无法处理,才会放到老年代
【6】如果老年代还放不下,就回进行全GC   FULL GC  这个性能非常慢
【7】优化就是避免发生FULL GC
******************************************************************************************
145、jconsole、jvisualvm(升级)使用
【1】cmd命令行海子街输入即可
【2】输入jvisualvm
【3】工具-插件-可用插件-检查最新版本
******************************************************************************************
146、中间件对性能的影响
【1】nginx就是中间件—>网关中间件—>
【2】docker stats 查看内存CPU的使用情况
【3】看到nginx主要是消耗CPU
【4】我的电脑比较牛批,吞吐量大
【5】过一个中间件,性能损失还是比较大的
【6】结论:中间件越多,性能损失越大,大多都损失到网络交互了
******************************************************************************************
147、压测业务功能-简单优化吞吐量测试
【1】中间件越多,性能损耗越大
【2】业务逻辑,db优化查询(自己经历过sql查比程序操作快太多了)、索引... 页面渲染导致拖慢
【3】静态资源加载
【4】日志打印也会损耗性能
【5】开缓存、建索引、关日志
******************************************************************************************
148、Nginx动静分离
【1】流程描述
动态请求---nginx---网关---微服务
静态资源---nginx(静态资源)
【2】nginx代理静态资源访问
规则:/static/**请求都有nginx返回
【3】mkdir static
cd /mydata/nginx/html/static
上传index文件
【4】修改nginx的配置
cd /mydata/nginx/conf/
cd conf.d/
vim my.conf
location /static/ {
       root /usr/share/nginx/html;
    }
【5】发现访问成功
******************************************************************************************
149、模拟线上应用内存崩溃宕机情况
【1】-Xmx1024m -Xms1024m -Xmn512m(新生代)
******************************************************************************************
150、三级分类数据获取
【1】数据多次查询变为一次,这玩意就是优化SQL查询
【2】果然还是术业有专攻,再牛逼的代码优化,不如SQL优化,性能是翻倍的快。

****************************************************************************************************************************************************************************

16、缓存
151、本地缓存与分布式缓存
【1】访问量且更新频率不高的数据
【2】即时性、数据一致性要求不高的数据
【3】最简单的缓存使用就是Map
private Map<String,object> tempMap=new HashMap<>();
判断缓存是否存在,存在使用缓存,否则不使用(放置缓存)
这个逻辑和我统计数据的逻辑简直一模一样,key value还是非常实用的,还能用containsKey...
【4】分布式系统就不能用本地缓存了....
需要使用缓存中间件了.............
老师这么一讲,感觉缓存也不复杂,包括集体公用缓存!!!!
分布式缓存:redis、redis分片、redis集群
******************************************************************************************
152、整合redis测试
【1】整合redis 引入redis-starter
使用redis的host信息,使用springboot自动配置好的
StringRedisTemplate
【2】不会多百度
package com.atguigu.gulimall.product.util;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

import javax.annotation.Resource;
import java.util.UUID;


@SpringBootTest
public class ZTest {
    @Resource
    StringRedisTemplate stringRedisTemplate; !!!!!!!!!!!!!!

    @Test
    public void testOne() {
        ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
        // 存储
        ops.set("keyOne", UUID.randomUUID() + "Hello");
        // 查询
        String res = ops.get("keyOne");
        System.out.println("redis之前保存的数据是" + res);
    }
}
******************************************************************************************
153、改造三级分类业务
【1】  @Resource
StringRedisTemplate stringRedisTemplate; !!!!!!!!!!!!!!
 ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
【2】ops.get("key")...
【3】存数据的规则,就是都存JSON数据
如Map,可以用JSON.toString(tempMap)
【4】从缓存中拿到的数据,JSON字符串要逆转为可用对象
Map<Object,Object> tempMap=JSON.paserObject(resJson,new TypeReference<>(){
    Map<Object,Object>
});
【5】这就是序列化和反序列化
******************************************************************************************
154、压力测试内存溢出和解决
【1】OutOfDirectMemoryError:堆外内存溢出
lettuce的bug导致内存溢出
【2】netty没有指定堆外内存,就会还是用-Xmx的值作为默认
【3】仅调大堆外内存没有用,只是延缓了时间,后面还是会报错
【4】解决方案,升级lettuce客户端。切换使用jedis
【5】添加依赖
  <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
【6】排除lettuce
  <!-- 引入redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
  <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
【7】升级或者更换,这是思路
【8】spring对letturce和jedis做了两次封装,所以都能用
******************************************************************************************
155、缓存击穿、穿透、雪崩
【1】缓存穿透:100万的访问,同时访问,到redis判断没有,直接到mysql,就崩了
解决:null结果缓存,并加入短暂过期时间
【2】缓存雪崩:已存的数据大面积生效
解决:过期时间加一个随机的值
  ops.set("keyOne", UUID.randomUUID() + "Hello", 1, TimeUnit.DAYS); // 一天以后再过期
【3】缓存击穿:访问热点key,当key刚好失效的时候,当大量请求正好过来时就击穿了
解决:加锁,只让一个人查询key
******************************************************************************************
156、正确的加锁,解决击穿问题
【1】Springboot所有的组件在容器中都是单例的
【2】单个容器加锁
 synchronized (this) {
            // 得到锁以后,应该去缓存中确定一次,如果没有才去执行查询
            res = ops.get("keyOne");
            if (!StringUtil.isEmpty(res)) { // 如果存在返回数据
                return res;
            }
            // 否则才去查询数据库
            // xxx
        }
或者JUC 的lock锁
【3】锁—>时序问题
解决:把放redis的操作也锁住!!!!!!!!!!!!!!!!!!
就解决了只查询一次,否则会导致锁的时序问题
******************************************************************************************
157、本地锁在分布式下的问题
【1】10001、10002、10003三个端口启动模拟
发现三个服务都查询了一次数据库
原因:就是this,只能锁着一个容器的进程,锁不住其他进程
******************************************************************************************
158、分布式锁的原理与使用(杀鸡不需要用牛刀)
【1】N个商品服务,同时的请求,只能有一个请求查数据库
【2】去公共的地方占坑,比如去redis站坑位
【3】所有的服务都去一个公共服务占坑,这就是原理
【4】set lock haha NX (多个窗口可以同时执行),结果是只有一个窗口能占用成功
3个 nil  一个OK
【5】withRedisLock
// 占用分布式锁
  boolean flag = Boolean.TRUE.equals(ops.setIfAbsent("lock", "lock"));
        if (flag) {
            System.out.println("加锁成功");
			 // 执行业务
            stringRedisTemplate.delete("lock");
        } else {
            // 加锁失败 重试
            // 休眠100ms
            Thread.sleep(100);
            return testOne(); // 自旋的方式
        }
        return res;
【6】存在的问题,执行业务逻辑异常,一直占坑没删锁,没删,就死锁了
解决:给锁设置自动过期时间,还是官方考虑的周全
// 占用分布式锁
  boolean flag = Boolean.TRUE.equals(ops.setIfAbsent("lock", "lock"));
        if (flag) {
            System.out.println("加锁成功");
			// 设置过期时间
			 stringRedisTemplate.expire("lock", 30, TimeUnit.SECONDS);
			 // 执行业务
            stringRedisTemplate.delete("lock");
        } else {
            // 加锁失败 重试
            // 休眠100ms
            Thread.sleep(100);
            return testOne(); // 自旋的方式
        }
        return res;
【7】如果在这段代码执行之前,突然断电,锁就是永远死锁了。
// 设置过期时间
stringRedisTemplate.expire("lock", 30, TimeUnit.SECONDS);
解决:还是需要保证原子性,就是两个操作的统一性。
set lock lock EX 300 NX
ttl lock
【8】最后的加锁,保证加锁和过期是原子性的
// 只要是同意把锁,就能锁着这把锁的所有线程
boolean flag = Boolean.TRUE.equals(ops.setIfAbsent("lock", "lock", 300, TimeUnit.SECONDS));
if (flag) {
System.out.println("加锁成功");
stringRedisTemplate.delete("lock");
// 执行业务
} else {
// 加锁失败 重试
// 休眠100ms
Thread.sleep(300);
return testOne(); // 自旋的方式
}
return res;
【9】删锁,业务超时,删除别人的锁...
站锁的时候,放置uuid
还是存在原子性问题.......所以闪烁也需要做成原子性操作
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Integer delRes = stringRedisTemplate.execute(new DefaultRedisScript<Integer>(script, Integer.class), Arrays.asList("lock"), token);
【10】锁的执行异常处理
try {
	// 执行业务
	System.out.println("do work");
} finally {
	String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
	Integer delRes = stringRedisTemplate.execute(new DefaultRedisScript<Integer>(script, Integer.class), Arrays.asList("lock"), token);
}
【11】原理:就是保证加锁解锁的原子性
******************************************************************************************
159、Redisson概述&整合
【1】官网推荐的redis的儿子
【2】引入依赖
<dependency>
	<groupId>org.redisson</groupId>
	<artifactId>redisson</artifactId>
	<version>3.12.0</version>
</dependency>
【3】配置redisson
package com.atguigu.gulimall.product.config;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;

@Configuration
public class MyRedissonConfig {
    @Bean(destroyMethod = "shutdown")
    public RedissonClient redisson() throws IOException {
        //1、创建配置
        Config config = new Config();
        config.useSingleServer().setAddress("redis://192.168.0.205:6379");
        //2、根据Config创建出RedissonClient实例
        //Redis url should start with redis:// or rediss://
        RedissonClient redissonClient = Redisson.create(config);
        return redissonClient;
    }
}
【4】使用
 @Resource
    RedissonClient redissonClient;

    @Test
    public void test2() {
        System.out.println(redissonClient);
    }
******************************************************************************************
160、Redisson的lock使用
【1】可重入锁,实现了JUC下的lock接口
舍得 舍得,有舍才有得,不然浪费了光阴,留住了寂寞
@Test
public void test2() {
	// 获取一把锁,只要名字一样,就是同一把锁
	RLock rLock = redissonClient.getLock("my_lock");
	rLock.lock(); // 阻塞等待
	try {
		System.out.println("加锁成功,执行业务..." + Thread.currentThread().getName());
		Thread.sleep(3000);
	} catch (Exception e) {
		e.printStackTrace();
	} finally { // 不管是否出现问题 都解锁
		System.out.println("释放锁" + Thread.currentThread().getName());
		rLock.unlock();
	}
}
【2】锁的自动续期,业务超长,会自动续30ms
【3】只要锁完成,即使不手动解锁,锁也会在30s后自动删除,不会死锁
******************************************************************************************
161、lock看门狗机制
【1】自己指定,不会自动续期,emmm 那还用??????
rLock.lock(10, TimeUnit.SECONDS); // 10秒自动解锁,自动解锁一定大于业务执行时间
【2】如果传递了锁了超市时间,就发送给redis执行脚本。
如果没有指定超时时间,默认走看门狗时间
【3】结论使用	rLock.lock(); // 阻塞等待
【4】如果明确判定业务时间,用指定也可以
******************************************************************************************
162、读写服务
【1】以redis为例
redisTemplate
  @Test
    public void test3() {
        RReadWriteLock rReadWriteLock = redissonClient.getReadWriteLock("rw_lock");
        String str = "";
        RLock rLock = rReadWriteLock.writeLock();
        try {
            // 该数据加写锁,读数据加读锁
            str = UUID.randomUUID().toString();
            rLock.lock();
            stringRedisTemplate.opsForValue().set("writeValue", str);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rLock.unlock();
        }
    }

    @Test
    public void test4() {
        RReadWriteLock rReadWriteLock = redissonClient.getReadWriteLock("rw_lock");
        RLock rLock = rReadWriteLock.readLock();
        rLock.lock();
        try {
            String res = stringRedisTemplate.opsForValue().get("writeValue");
            System.out.println(res);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rLock.unlock();
        }
    }
【2】实现效果:就是避免,保证一定能读到最新的数据,修改期间写锁是一个排他锁
******************************************************************************************
163、读写锁补充
【1】学习过就忘记,说明什么?没有应用太容易忘记了,容易造成无效学习...
【2】读+写:读写释放,写锁就会加载成功
 ******************************************************************************************
 164、闭锁
 【1】放假,学校锁门,假如有5个班全部走完,我们才可以锁大门
  @Test
    public void test5() throws Exception {
        RCountDownLatch rCountDownLatch = redissonClient.getCountDownLatch("door");
        rCountDownLatch.trySetCount(5);
        rCountDownLatch.await();
        System.out.println("放假了...");
    }
    public void work() {
        RCountDownLatch rCountDownLatch = redissonClient.getCountDownLatch("door");
        rCountDownLatch.countDown(); // 计数-1
        System.out.println("班级所有人都走了...");
    }
【2】当work执行5次后,才能锁门
【3】说明什么呢?说明需要学习redis
 ******************************************************************************************
165、信号量
【1】车库停车,3个停车位
【2】redis存了一个总值,acquire是-1,release是+1
   @Test
    public void test6() throws Exception {
        RSemaphore rSemaphore = redissonClient.getSemaphore("stop");
        rSemaphore.acquire(); // 获取一个值,实际场景就是占用一个车位
        System.out.println("获取成功...");
    }

    @Test
    public void test7() throws Exception {
        RSemaphore rSemaphore = redissonClient.getSemaphore("stop");
        rSemaphore.release(); //释放一个值,实际场景就是让出一个车位
        System.out.println("让车位成功...");
    }
【3】信号量后期可以用于限流
 boolean flag= rSemaphore.tryAcquire(); // 尝试获取,不行就算了
******************************************************************************************
166、分布式锁-缓存一致性问题解决
【1】双写模式,保证执行顺序,就是需要加锁
【2】失效模式
【3】读数据也能保证拿到最新的数据
【4】缓存加上过去时间,每过一段时间主动更新即可
【5】通过加锁保证并发读写
【6】最终就是过期时间+读写锁就可以了
【7】Canal
******************************************************************************************
167、SpringCache的概述
【1】 有名称的划分空间
******************************************************************************************
168、整合SpringCache
【1】引入依赖
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
【2】xxx.properties配置
spring.cache.type=redis
【3】测试使用缓存
开启缓存功能@EnableCaching
******************************************************************************************
169、@Cacheable细节
【1】尼玛视频真模糊 草拟马
******************************************************************************************
170、自定义缓存配置 4分钟
【1】RedisCacheConfiguration
package com.black.config;

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
@EnableCaching
public class MyCacheConfig {
    @Bean
    RedisCacheConfiguration redisCacheConfiguration() {
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
        redisCacheConfiguration = redisCacheConfiguration.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
        redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        return redisCacheConfiguration;
    }
}
【2】缓存的数据是否用了JSON的格式
【3】结论是:先过一遍终极,然后路漫漫其修远兮,用到的才是能理解的东西
******************************************************************************************
171、CacheEvict
【1】@Cacheable,说明redis还是需要学习
******************************************************************************************
172、SpringCache原理与不足
【1】缓存穿透
【2】缓存击穿
【3】缓存雪崩
【4】请问老师是怎么记住这些东西的,卧槽!!!!!!!
【5】不跟着写代码了,太鸡儿乱了!!!!!!!!

****************************************************************************************************************************************************************************

17、检索服务
173、搭建页面环境
【1】搭建页面
【2】nginx
******************************************************************************************
174、调整页面跳转
【1】从搜索页跳转到首页
******************************************************************************************
175、搜索查询参数模型分析抽取
【1】接口、实现类 3分钟
【2】ID、关键字、组合查询、排序
【3】价格。热度、排序、过滤、聚合==
******************************************************************************************
176、检索返回结果
【1】品牌信息
【2】分类信息
【3】属性
******************************************************************************************
177、检索DSL测试
【1】kibana去测试
【2】sort排序
【3】是否有货
******************************************************************************************
178、DSL测试-聚合部分
【1】attrs
【2】根据名字聚合
【3】再看其他属性的聚合
******************************************************************************************
179、SearchRequest构建
【1】模糊匹配、过滤
【2】排序 分页 高亮 聚合分析
【3】三级id 品牌id 指定属性查询 库存查询等
【4】结论学习es
******************************************************************************************
180、SearchRequest分页 高亮 聚合分析
【1】分页
【2】高亮
【3】from to 
******************************************************************************************
181、SearchRequest构建聚合
【1】aggregation
【2】聚合attrName attrValue
******************************************************************************************
182、SearchRequest分析&封装
【1】虽然高级,但是页码的计算和我的计算逻辑是一样的
【2】没想到多年前的果实,多年后同样可以进行使用
【3】说明思考的精华才最重要,盲目用插件就是跟风别人
【4】分类、品牌
【5】属性id 属性名字 属性所有值
******************************************************************************************
183、验证封装结果正确性
【1】所有的封装都不如简化思想
【2】利用字段的聚合+split拆分,即可拆分出复杂数据结构的东西
【3】在实际使用中这种思路简单实用,利于快速解决问题
******************************************************************************************
184、页面基本数据渲染
【1】展示名称、描述、价格等
【2】什么年代了,还用thymeleaf...
******************************************************************************************
185、页面筛选条件渲染
【1】跳转指定方法,动态取值,用VUE直接解决不香吗
【2】感觉人有精益求精才可敬,无论干什么职业,这种精神是值得学习的
【3】indexOf,判断字符在字符串中的位置,小方法在业务中往往有大作用
******************************************************************************************
186、页面分页数据渲染
【1】thymeleaf判断下一页,我是判断过的,这时候VUE有话说...
【2】果然实现的思路和我最早的一样
******************************************************************************************
187、页面排序功能
【1】我还以为排序不需要数据库呢,笑死
【2】按照谁排序加个颜色,这种交互还是不错的,可以的
******************************************************************************************
188、页面排序字段回显
【1】学完VUE,thymeleaf真是没法看呀,我的哥
【2】endWith的使用
******************************************************************************************
189、页面价格区间
【1】查询多少到多少之间的
【2】substring方法,小方法大作用,多次说明了这个道理
【3】是否有库存+状态回显
******************************************************************************************
190、面包屑导航
【1】VUE实现非常简单
【2】我总感觉services imp很不直接 哈哈
******************************************************************************************
191、条件删除与URL编码问题
【1】URLEncoder.encode
【2】面包屑导航
【3】海思、华为国产之光
******************************************************************************************
192、条件筛选联动
【1】实体类
【2】条件判断多条件状态
【3】标记多个条件的true false

****************************************************************************************************************************************************************************

18、异步
193、异步复习
【1】Thread、Runnable、Callable
public class ZTest {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }

    static class MyThread extends Thread {
        public void run() {
            System.out.println("当前线程" + Thread.currentThread().getName());
            int i = 10 / 2;
            System.out.println("运行结果" + i);
        }
    }
}
【2】三种线程
package com.black.util;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

/*
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class ZTest {
    @Test
    public void test1() {

    }
}*/
public class ZTest {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();

        MyRunnable myRunnable = new MyRunnable();
        new Thread(myRunnable).start();

        FutureTask<Integer> futureTask = new FutureTask<>(new MyCallable());
        new Thread(futureTask).start();
    }

    static class MyThread extends Thread {
        public void run() {
            System.out.println("当前线程" + Thread.currentThread().getName());
            int i = 10 / 2;
            System.out.println("运行结果" + i);
        }
    }

    static class MyRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("当前线程" + Thread.currentThread().getName());
            int i = 10 / 2;
            System.out.println("运行结果" + i);
        }
    }

    static class MyCallable implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程" + Thread.currentThread().getName());
            int i = 10 / 2;
            System.out.println("运行结果" + i);
            return i;
        }
    }
}
【3】异步任务
FutureTask<Integer> futureTask = new FutureTask<>(new MyCallable());
new Thread(futureTask).start();
********************************************************************************
 static class MyCallable implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程" + Thread.currentThread().getName());
            int i = 10 / 2;
            System.out.println("运行结果" + i);
            return i;
        }
    }
【4】线程池,业务里面三种都不用,应该用线程池的方式!!!!!!!!!!
这是资源控制。性能稳定
******************************************************************************************
194、线程池详解
【1】七大参数
核心线程数:new N个Thread()
maximumPoolSize:最大线程数量
keepAliveTime:空闲大于多少时间,就释放,超过核心线程数的部分
unit:时间单位
BlockQueue:阻塞队列
threadFactory:线程的创建工厂
RejectExecutionHandler:如果队列满了,按照指定的拒绝策略执行
【2】如何核心线程数满了,任务会先放到队列,空闲再执行。
队列满了,会开新队列,不会超过maximumPoolSize
【3】新开队列满了,会启动拒绝策略
******************************************************************************************
195、CompletableFuture异步编排
【1】六个异步,如果顺序执行,会很久,如果同时,只需要执行一个最大的
【2】类似于VUE的promise
******************************************************************************************
196、CompletableFuture使用
【1】执行的具体的示例
package com.black.util;

import java.util.concurrent.*;

/*
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class ZTest {
    @Test
    public void test1() {

    }
}*/
public class ZTest {
    public static final ExecutorService executorService = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws Exception {
        System.out.println("main start");
        /*CompletableFuture.runAsync(() -> {
            System.out.println("当前线程" + Thread.currentThread().getName());
            int i = 10 / 2;
            System.out.println("运行结果" + i);
        }, executorService);*/
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程" + Thread.currentThread().getName());
            int i = 10 / 2;
            System.out.println("运行结果" + i);
            return i;
        }, executorService);
        System.out.println("main end..." + completableFuture.get());
    }
}
******************************************************************************************
197、CompletableFuture完成回调与异常感知
【1】拿到结果和异常处理
package com.black.util;

import java.util.concurrent.*;

/*
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class ZTest {
    @Test
    public void test1() {

    }
}*/
public class ZTest {
    public static final ExecutorService executorService = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws Exception {
        System.out.println("main start");
        /*CompletableFuture.runAsync(() -> {
            System.out.println("当前线程" + Thread.currentThread().getName());
            int i = 10 / 2;
            System.out.println("运行结果" + i);
        }, executorService);*/
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程" + Thread.currentThread().getName());
            int i = 10 / 0;
            System.out.println("运行结果" + i);
            return i;
        }, executorService).whenComplete((res, e) -> {
            System.out.println("异步任务成功完成....结果是:" + res + " 异常是:" + e);
        }).exceptionally(throwable -> {
            return 10; // 出现异常的默认返回值,可以修改返回值
        });
        System.out.println("main end..." + completableFuture.get());
    }
}
******************************************************************************************
198、CompletableFuture-handle最终处理
【1】这个好用呀!!!!!!!!!!!!!!!!!!!!!!
package com.black.util;

import java.util.concurrent.*;

/*
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class ZTest {
    @Test
    public void test1() {

    }
}*/
public class ZTest {
    public static final ExecutorService executorService = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws Exception {
        System.out.println("main start");
        /*CompletableFuture.runAsync(() -> {
            System.out.println("当前线程" + Thread.currentThread().getName());
            int i = 10 / 2;
            System.out.println("运行结果" + i);
        }, executorService);*/
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程" + Thread.currentThread().getName());
            int i = 10 / 2;
            System.out.println("运行结果" + i);
            return i;
        }, executorService).handle((res, e) -> {
            if (res != null) {
                return res * 2;
            }
            if (e != null) {
                return 0;
            }
            return 0;
        });
        System.out.println("main end..." + completableFuture.get());
    }
}
******************************************************************************************
199、CompletableFuture-线程串口化
【1】不是不用串口化执行吗
【2】当A需要B的结果时,可以用这种思路
【3】thenAcceptAsync(res->{
     System.out.println("任务2启动..."+res)
})
【4】thenApplyAsync  即用也有返回值
******************************************************************************************
200、CompletableFuture-两个任务组合:都要完成
【1】thenCombine 组合两个future
【2】f1.runAfterBothAsync(f2,()->{
 System.out.println("任务3开始...")
}
)
【3】thenAcceptBothAsync(f1,f2)
******************************************************************************************
201、两个任务组合,一个完成就继续执行
【1】applyToEither
【2】 acceptEitherAysnc
【3】applyToEitherAsync
******************************************************************************************
202、多任务组合
【1】多个任务都执行完毕才继续执行
【2】CompletableFuture.allOf(f1,f2,f3....)
【3】anyOf 有一个成功就继续执行

****************************************************************************************************************************************************************************

19、商品详情
203、环境搭建
【1】根据id指定商品详情页面
******************************************************************************************
204、模型抽取
【1】商品的参数获取
【2】概述、规格包装...
【3】其实每一个都可以用文本字段标记,然后拆分,这样逻辑最清晰
******************************************************************************************
205、规格参数
【1】各种组合查询规格参数,如果不是大型项目完全没必要
【2】用一个json表示一个商品不是更香吗,老师查了至少8个表....
【3】设计数据库名字代表含义,字段1-99挺好的,这样更容易记忆和理解
******************************************************************************************
206、销售属性组合
【1】颜色
【2】屏幕
******************************************************************************************
207、详情页渲染
【1】比如移入展示大图等
【2】图片集合
【3】还是青戈的思路简单清晰,这才是大道之行,为了解决问题而去的
******************************************************************************************
208、销售属性渲染
【1】MYSQL的使用很重要,比如group by des...
【2】mybatis 自定义封装
【3】选中样式的标记
******************************************************************************************
209、SKU组合切换
【1】点击黑色,关联图片切换等
【2】都是前段逻辑页面的编写,现实中估计也没有这么复杂的逻辑,跟着敲一遍的意义是什么
******************************************************************************************
210、异步编排优化
【1】ThreadPoolExecutor
【2】让他可以配置

****************************************************************************************************************************************************************************

20、认证服务
211、环境搭建
【1】nacos
【2】Auth
******************************************************************************************
212、验证码
【1】立即注册、注册页面
【2】倒计时,多少秒后还能验证,这都是多久前的前端处理逻辑了...
******************************************************************************************
213、发送手机短信验证码
【1】阿里云还有免费的短信接口...
******************************************************************************************
214、验证码防刷校验
【1】10分钟不刷新,同一个手机号
******************************************************************************************
215、注册页面环境
【1】注册页面前端校验、后端校验
【2】VUE实现很方便的,emmm
【3】让我感觉回到了serverlet的时候...
【4】回显、带数据老师的知识都太老了,emmm
******************************************************************************************
216、异常机制
【1】邮箱唯一性检查
【2】手机号唯一性检查
【3】检查不通过则抛出异常(数据库存在就是不通过)
******************************************************************************************
217、密码的加密存储,MD5&代盐&BCrypt
【1】果然sha256更先进
【2】随机值加密,这时候数据库里就需要额外存个盐字段
【3】用一个sha256不可逆就OK了 卧槽
******************************************************************************************
218、注册完成
【1】实现完整的注册流程
******************************************************************************************
219、账号密码登录功能完成
【1】这个逻辑自己的不是更香吗,卧槽!!!!
【2】老师搁这搁这呢
【3】老师是远程登录,碉堡了
******************************************************************************************
220、OAuth2.0概述
【1】社交账号登录:QQ、微信、微博
【2】三方登录没事确实可以学习下,青戈过来 哈哈哈
【3】细节我母鸡,肯定是三方暴露的接口
******************************************************************************************
221、以微博登录为例
【1】引导用户到微博授权页面
【2】登录成功后同意授权
******************************************************************************************
222、社交登录回调
【1】只要登录,就能换取TOKEN
******************************************************************************************
223、社交登录完成
【1】通过社交账号可以查询昵称、性别....
******************************************************************************************
224、社交登录测试成功
【1】点击登录-社交登录
【2】登录成功后跳转回首页
******************************************************************************************
225、分布式session不共享不同步问题
【1】多个服务器,session不同步的问题
******************************************************************************************
226、session不同步解决方案原理
【1】复制方案模式,session保存
【2】服务器不存session,浏览器自己保存,比较危险
【3】hash一致性
ip_hash,同一个ip全部落在同一个服务器
【4】终极解决:统一存储!!!!!!!!!!!!!!!!!!!!!!!!!!!
session统一存储,统一存储到redis/db
【5】子域名发卡,父域名使用
******************************************************************************************
227、SpringSession
【1】redis地址配置
spring.session.store-type=redis
spring.servlet.session.timeout=30m
【2】@EnableReidsHttpSession
【3】这块后期利用项目还真可以认真研究下
【4】使用JSON序列化存储
******************************************************************************************
228、自定义完成子域session共享
【1】配置session类
******************************************************************************************
229、springsession原理
【1】doFilterInternal
【2】对原有的session做了包装
******************************************************************************************
230、页面效果完成
【1】session不为空直接显示
【2】如果为空显示请登录
【3】登录后再访问登录页,应该直接登录,逻辑根据实际定吧
******************************************************************************************
231、单点登录概述
【1】一处登陆,处处登录
******************************************************************************************
232、单点登录框架演示
【1】单点登录服务器
【2】感觉需要吗?
【3】需要,微服务的时候需要这个单点登录,emmm,这得是非常大的服务了
【4】光登录就需要多个服务器...
******************************************************************************************
233、单点登录流程-1
【1】中央认证服务器,登录成功跳转回来
【2】只要有一个登录,其他的都不用登录
【3】全局统一一个sso-sessionid,所有系统的域名不相同
【4】实时证明前后端分离是对的,不然逻辑太乱了,切来切去的
******************************************************************************************
234、单点登录流程-2
【1】type 还hide呢,多老的技术了呀,卧槽
【2】登录成功会返回令牌,令牌会在地址栏携带
******************************************************************************************
235、单点登录流程-3
【1】sso_token 给浏览器保存一个cookie
【2】reponse.addCookie(sso_token)
【3】浏览器访问这个域名,都要带上这个域名下的所有cookie
【4】服务器判断浏览器是否携带cookie,如果携带了cookie,直接就跳过去
【5】这样就实现了,不同域名的登录了,思想很牛逼!!!!!!!!!!!
【6】给登录服务器留下redis登录信息、token重定向url带上、浏览器存token、服务端判断是否带token

****************************************************************************************************************************************************************************

21、购物车
236、环境搭建
【1】就是静态页面的编写
******************************************************************************************
237、数据模型分析
【1】购物车需求
【2】方式localstorage cookie websql 放入redis
【3】购物车的增删改查
【4】修改商品数量
【5】购物车的数据放到reids nosql
【6】redis!!!!!!!!!!!!!!!!
【7】redis存储的数据结构应该是什么样子的?
【8】每一个购物项信息,都是一个对象,以JSON的形式存储
******************************************************************************************
238、VO编写
【1】BigDecimal
【2】计算放到前端不好吗,为什么放在后端计算...
******************************************************************************************
239、ThreadLocal用户身份鉴别
【1】cookie的使用还是结合的略深
【2】同一个线程共享数据
【3】原理就是Map<Thread,Object>
******************************************************************************************
240、页面环境搭建
【1】购物车之间页面的跳转
******************************************************************************************
241、添加购物车
【1】加入购物车,这个就是对应用户redis加一个购物对象吗
******************************************************************************************
242、添加购物车细节
【1】这么简单的页面,讲的这么复杂 emmm,看来还得是VUE
******************************************************************************************
243、RedirectAttribute
【1】重定向
【2】重定向这个技术,感觉不实用,有了VUE就更不需要了
******************************************************************************************
244、获取合并购物车
【1】登录后的和未登录的购物商品进行合并
******************************************************************************************
245、选中购物项
【1】选中后修改redis里的状态
******************************************************************************************
246、改变购物项数量
【1】根据商品ID修改数量
******************************************************************************************
247、删除购物项
【1】删除hash的key

****************************************************************************************************************************************************************************

22、消息队列
248、RMQ作用
【1】先进后出、先进先出
【2】使用场景:异步处理(缩短响应时间、还能把插入成功放到rmq,然后直接返回成功)
【3】注册场景更直观的感知这个过程。
插入库---发注册邮件---发注册短信
插入库---(线程1发送注册邮件、线程2发注册短信)
插入库---消息给RMQ(同步返回告诉用户成功)---rmq再去线程1发送注册邮件、线程2发注册短信
【4】流量控制(流量削峰)
******************************************************************************************
249、RMQ概述
【1】消息代理
【2】目的地
【3】两种形式目的地:队列、主题
【4】JMS---AMQP
【5】AMQP是跨语言跨平台的
【6】RMQ
【7】springboot做了很好的兼容
【8】市面上的MQ产品 AMQ RMQ RocketMQ Kafka
******************************************************************************************
250、RMQ的工作流程
【1】Message头(route-key) + 体
【2】Publisher 生产者
【3】Exchange
【4】Broker 消息服务器---Exchange(交换机)--binding-对应多个Queue(类似电脑)
【5】Consumer 消费者,消费者客户端和服务器只会建立一条链接(长链接Connection)
【6】Channel(1个Connection包含多个Channel)
【7】虚拟主机 VHost
******************************************************************************************
251、RMQ的安装(基于Docker)
【1】docker run -d --name rabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p 25672:25672 -p 15671:15671 -p 15672:15672 rabbitmq:management
直接启动容易,会自动下载镜像
【2】docker update rabbitmq --restart=always  设置自启动
【3】http://192.168.0.205:15672/#/
账号密码登录:guest guest
******************************************************************************************
252、Exchange类型
【1】类型direct fanout topic headers
【2】direct(精准) fanout(广播模式) topic(选择性广播) 主要使用
【3】direct  交换机---队列---绑定交换机与队列
******************************************************************************************
253、Direct-Exchange
【1】建立了四个队列(direct_computer...)
【2】1个交换机绑定这四个队列
******************************************************************************************
254、Fanout-Exchange
【1】用Fanout类型交换机绑定四个队列
【2】交换机发送后,四个队列都收到了消息,写不写route-key都不影响
******************************************************************************************
255、Topic-Exchange
【1】Topic发送 决定是否能接收的是routing key,而不是电脑名称,当然当电脑名称和
routingkey一致时就能理解为一样的。
【2】所以电脑名称(队列名称),routing key应该尽量简单而非复杂
******************************************************************************************
256、Springboot整合RMQ
【1】引入包 spring-boot-starter-amqp
【2】引入后配置就自动生效
【3】@EnableRabbit
【4】# 配置RMQ
spring.rabbitmq.host=192.168.0.205
spring.rabbitmq.port=5672           注意!!!!!!!!!!!!!!
spring.rabbitmq.virtual-host=/
******************************************************************************************
257、AmqpAdmin的使用
【1】主要是测试代码
package com.black.util;

import org.junit.jupiter.api.Test;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest
public class ZTest {
    @Resource
    AmqpAdmin amqpAdmin;

    @Test
    public void createExchange() { // 创建交换机
        DirectExchange directExchange = new DirectExchange("java_exchange", true, false); // 直接交换机
        amqpAdmin.declareExchange(directExchange);
        System.out.println("java_exchange交换机创建完成...");
    }

    @Test
    public void createQueue() { // 创建计算机
        Queue queue = new Queue("java_computer", true, false, false);
        amqpAdmin.declareQueue(queue);
        System.out.println("java_computer队列创建完成...");
    }

    @Test
    public void createBinding() { // 绑定
        Binding binding = new Binding("java_computer", Binding.DestinationType.QUEUE, "java_exchange",
                "java_computer", null);
        amqpAdmin.declareBinding(binding);
        System.out.println("java_exchange 绑定 java_computer创建完成...");
    }
}
******************************************************************************************
258、RabbitTemplate的使用
【1】配置发送对象转JSON!!!!!!!!!!!!!!!!!!!!!
package com.black.config;

import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyRMQConfig {
    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }
}
【2】总体测试代码
package com.black.util;

import com.black.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest
public class ZTest {
    @Resource
    AmqpAdmin amqpAdmin;

    @Test
    public void createExchange() { // 创建交换机
        DirectExchange directExchange = new DirectExchange("java_exchange", true, false); // 直接交换机
        amqpAdmin.declareExchange(directExchange);
        System.out.println("java_exchange交换机创建完成...");
    }

    @Test
    public void createQueue() { // 创建计算机
        Queue queue = new Queue("java_computer", true, false, false);
        amqpAdmin.declareQueue(queue);
        System.out.println("java_computer队列创建完成...");
    }

    @Test
    public void createBinding() { // 绑定
        Binding binding = new Binding("java_computer", Binding.DestinationType.QUEUE, "java_exchange", "java_computer", null);
        amqpAdmin.declareBinding(binding);
        System.out.println("java_exchange 绑定 java_computer创建完成...");
    }

    @Resource
    RabbitTemplate rabbitTemplate;

    @Test
    public void send() {
        User user = new User(); // User必须要序列化,因为发送必须implements Serializable,可以通过配置发送json(而且可以对象不序列化)
        user.setName("RMQ");
        user.setId(10086);
        user.setEmail("wdfgdzx@163.com");
        String msg = "Hello send msg";
        rabbitTemplate.convertAndSend("java_exchange", "java_computer", user);
        System.out.println("消息发送完成..." + user);
    }
}
******************************************************************************************
259、RabbitListener&RabbitHandler接收消息
【1】RMQ监听器,这两个的组合使用可以接收不同类型的消息
    // 3、@RabbitLister 类+方法上
    // 4、@RabbitHandler 标在方法上
【2】实际使用示例类
package com.black.service.impl;

import com.black.pojo.User;
import com.black.service.PageService;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;

@Service("PageService")
public class PageServiceImpl implements PageService {
    // 订单服务启动多个
    // 1、同一个消息只能有一个服务收到
    // 2、模拟业务处理耗时  只有前一个接收到的消息处理完毕,才能接收下一个消息。
    // 3、@RabbitLister 类+方法上
    // 4、@RabbitHandler 标在方法上(重载区分不同的消息)

    @RabbitListener(queues = {"java_computer"})
    public void acceptMessage(Message message, User user, Channel channel) {
        System.out.println("接收到消息..." + message);
        System.out.println("接收到真实内容..." + user);
        System.out.println("通道..." + channel);
    }

    @Override
    public Integer getCurrentPage() {
        return null;
    }

    @Override
    public void setCurrentPage(Integer integer) {

    }

    @Override
    public Integer getPageSize() {
        return null;
    }

    @Override
    public void setStart(Integer integer) {

    }

    @Override
    public void setEnd(Integer integer) {

    }
}
******************************************************************************************
260、可靠投递-发送端确认
【1】消息确认机制
【2】publishers发送者们   consumers消费者们
【3】通过回调的方式确认。
confirmCallback 确认模式 (表示服务器收到消息)
returnCallback 退回模式(表示给电脑端队列成功)
ack机制
【4】配置properties
# 配置RMQ
spring.rabbitmq.host=192.168.0.205
spring.rabbitmq.port=5672
spring.rabbitmq.virtual-host=/
# 开启确认
spring.rabbitmq.publisher-confirm-type=correlated
【5】配置类
package com.black.config;

import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

@Configuration
public class MyRMQConfig {
    @Resource
    RabbitTemplate rabbitTemplate;

    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }

    @PostConstruct // 对象创建完成以后,执行这个方法
    public void initRabbitTemplate() {
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String s) {
                System.out.println("confirm..." + correlationData);
                System.out.println("结果..." + ack);
                System.out.println("原因..." + s);
            }
        });
    }
}
【6】配置还有点问题,学实战吧
【7】队列的抵达确认
******************************************************************************************
261、消费端确认机制(也需要properties也配置开启)
【1】手动ack消息
【2】如何签收
【3】如何拒绝、如何退回

****************************************************************************************************************************************************************************

23、订单服务
261、页面环境搭建
【1】静态资源放到nginx里面
【2】前端页面的搭建
******************************************************************************************
262、整个SpringSession
【1】导入依赖
【2】页面用户名动态从session取
******************************************************************************************
263、订单基本概念
【1】订单包含的信息
【2】订单的状态
【3】订单-出库-售后
【4】幂等性处理
******************************************************************************************
264、订单登录拦截
【1】就是普通的登录拦截器
【2】根据是否登录判断是否需要跳转到登录页面
******************************************************************************************
265、订单确认页模型抽取
【1】配送方式
【2】送货清单
******************************************************************************************
266、订单确认页面数据获取
【1】获取收货地址列表
【2】获取购物车里的数据
【3】从数据库获取最新数据(比如最新价格)
******************************************************************************************
267、Feign远程调用丢失请求头问题
【1】没有请求头,系统会认为未登录
【2】加上feign远程调用的请求拦截器!!!!!!!!!!!!!
【3】在拦截器远程之前,先设置之前的请求头并携带
******************************************************************************************
268、Feign异步调用丢失请求头问题
【1】ThreadLocal
【2】由于从OrderService开始并发出了3个线程,所以HttpServetRequest就有的为空了
【3】解决方法就是,每个线程开始之前,set下请求头!!!!!!!!!!!
******************************************************************************************
269、BUG修改
【1】返回包装对象
******************************************************************************************
270、订单确认页渲染
【1】收货人信息
【2】姓名、地址
【3】商品区域
【4】就是前端动态解析商品对象的信息并展示
******************************************************************************************
271、确认页面库存查询
【1】查询商品是否有货
【2】Collectors.toMap()  还能这么用,碉堡了
******************************************************************************************
272、模拟运费效果
【1】获取运费信息的方法
【2】运费的计算
******************************************************************************************
274、细节显示
【1】收货人信息、地址信息
******************************************************************************************
275、接口幂等性讨论
【1】提交订单的幂等性,提交一次和提交100次是一样的
【2】特别是支付请求,更要是一样的
【3】微服务之间的调用
【4】select * form xxx 是天然幂等的
【5】令牌机制,先删除令牌然后再执行操作
【6】getToken==token&&delToken 是一个不可分割的部分,才能保证幂等性
【7】全局请求唯一ID
******************************************************************************************
276、订单确认页完成
【1】30分钟TOKEN过期
【2】无需提交需要购买的商品,去购物车再次回去即可
******************************************************************************************
277、原子验令牌
【1】redisToken不能为空
【2】令牌的对比和删除必须保证原子性(使用脚本的方式操作)
【3】验证成功做一些业务处理
******************************************************************************************
278、构造订单数据
【1】创建订单号
【2】生成订单号
【3】获取地址信息
【4】页面传递数据对象封装
【5】数量、城市、详细地址、收货人名称
【6】先创建订单、再创建订单项,再计算金额
******************************************************************************************
279、构造订单项数据
【1】最后确认购物项的价格
【2】订单号、SPU、SKU、优惠信息、积分信息
******************************************************************************************
280、订单验证价格
【1】computePrice计算价格
【2】单价乘以数量
【3】折扣、优惠券、积分总体作用后的价格
【4】页面提交价格与后台计算价格比对下
******************************************************************************************
281、保存订单数据
【1】只要有异常,就回滚订单数据
******************************************************************************************
282、锁定库存
【1】按照下单地址,找到一个就近仓库,锁定库存
【2】找到每个商品在哪个仓库有库存
【3】锁定库存的sql语句
******************************************************************************************
283、提交订单的问题
【1】全局异常处理等
【2】商品库存不足就不会创建订单

****************************************************************************************************************************************************************************

 24、分布式事务
 284、本地事务在分布式下的问题
 【1】保存订单
 【2】远程锁库存
 【3】远程减库存了,后面异常;
 【4】网络问题最容易导致分布式事务问题
 【5】很容易订单回归,但是库存没有回滚
******************************************************************************************
 285、本地事务隔离级别&传播行为
 【1】原子性、一致性、隔离性、持久性
 【2】isolation=xxx 调整隔离级别
******************************************************************************************
 286、分布式CAP&Raft原理
 【1】库存服务、订单服务、账号服务
 【2】CAP定理
 【3】最终保障的是AP原理
 【4】Raft
 【5】Leader Election
 【6】红颜色代表未提交状态
 【7】黑颜色就是提交了
 【8】领导选举+日志复制+同步执行
 【9】自动投票机制,这样才能保证集群的数据一致性
 【10】自动检测心跳+自旋投票+多轮投票最终能选出一个唯一领导
 【11】我先不说这个技术,单说这个思路就牛批!!!!!!!!!!!!!!!
******************************************************************************************
 287、BASE
 【1】对CPA理论的延伸
 【2】强一致性、弱一致性、最终一致性
******************************************************************************************
 288、分布式事务常见解决方案
 【1】柔性事物 实现最终一致性
 【2】TCC事务补偿方案
 【3】最大努力通知方案
******************************************************************************************
 289、Seata&环境准备
 【1】TC TM RM
 【2】每一个加上一个回滚日志表undo_lock
******************************************************************************************
 290、Seata分布式事务体验
 【1】registry.conf
 【2】file.conf
 【3】加压使用seata-server
 ******************************************************************************************
 291、最终一致性库存解锁逻辑
 【1】要使用各种锁的
 【2】延迟队列

****************************************************************************************************************************************************************************

25、订单服务-2
292、RabbitMQ延时队列
【1】下订单  30min没有支付 则关闭订单
【2】锁库存  40min检查订单不存在或者取消,这释放库存
【3】延时队列实现1
******************************************************************************************
293、延时队列定时关闭订单模拟
【1】交换机、队列
【2】在MyRMQConfig用@Bean的形式创建消息中间件的组件
【3】@RabbitListener 监听上
******************************************************************************************
294、创建业务交换机&队列
【1】Exchange交换机(使用Topic类型)
【2】延时交换机(死信交换机)
【3】商品服务、检索服务、seata
******************************************************************************************
295、库存自动解锁代码
【1】库存工作单、工作单详情表
【2】lombok的使用
【3】@Data很重要
******************************************************************************************
296、库存解锁逻辑
【1】没有这个订单必须解锁
【2】有这个订单,已取消解锁库存,没取消不能解锁
【3】没有这么多经验,想一下子终极还是有很大难度的。
【4】远程调用订单服务,查询订单的状态
【5】调用unLockStock方法
【6】如果订单正常,消息重新放回
******************************************************************************************
297、库存自动解锁完成
【1】channel.basicAck(xxx)
******************************************************************************************
298、测试自动解锁
【1】unLockStock
******************************************************************************************
299、定时关闭订单功能完成
【1】@RabbitHandler 看来定时功能都需要RMQ 消息中间件呀
【2】订单考虑到网络延迟卡顿,设计逻辑还挺复杂的
【3】为了解决这个问题,就再需要一个消息通道,@RabbitHandler
【4】消息通道解锁时,查询下最新库存状态,放置重复解锁
******************************************************************************************
300、消息丢失、积压、重复等解决方案
【1】try catch
【2】给数据库保存每一条消息的发送记录,定期扫记录,重新发
【3】消息抵达Broker,但是Broker宕机了。所以需要使用Publisher模式,如果returnedMessage
发生错误就修改数据库的记录状态。
【4】消息重复  ack没有成功的状态。
【5】消息积压:上线更多的消费者。上线专门的队列消息服务。

****************************************************************************************************************************************************************************

26、支付 
301、支付宝沙箱支付&代码
【1】 支付宝开放平台
******************************************************************************************
302、支付宝RSA、加密加签、密匙等
【1】四把钥匙保证了安全(商家公钥私钥)(支付宝公钥私钥)
******************************************************************************************
303、内网穿透
【1】哲西云
【2】这个老师都能将18分钟,服气 服气

****************************************************************************************************************************************************************************

27、订单服务-3
304、整合支付需要注意的问题
【1】编码UTF-8
******************************************************************************************
305、整合支付
【1】和青戈比不够直接,就是整合支付,讲这么久...
******************************************************************************************
306、支付成功同步回调
【1】支付成功
******************************************************************************************
307、订单列表页渲染完成
【1】订单状态,订单项的遍历
******************************************************************************************
308、异步通知内网穿透环境搭建
【1】分布式事务(支付宝的通知)
******************************************************************************************
309、支付完成&收单
【1】支付宝的扫码支付页面(账号 密码支付页面)

****************************************************************************************************************************************************************************

28、秒杀服务
311、后台添加秒杀商品
【1】限流+异步+缓存
【2】新增秒杀商品明细
******************************************************************************************
312、定时任务&Cron表达式
【1】定时任务场景
【2】cron表达式 和Linux一样呀
【3】世界上太多的知识,你不可能都掌握,但是在你需要的时候你要会用
【4】可以使用在线工具生成表达式
******************************************************************************************
313、Springboot整合定时任务
【1】@EnableScheduling
@Scheduled(cron="* * * * * ?")
public void printHell(){
   System.out.println("Hello");
}
【2】定时任务不应该阻塞 
【3】定时任务线程池子 @EnableAsync
@Async
@Scheduled(cron="* * * * * ?")
public void printHell(){
   System.out.println("Hello");
}
******************************************************************************************
314、时间日期处理
【1】秒杀商品定时上架,每天晚上3点上架
【2】@EnableFeginClients 开启远程调用
******************************************************************************************
315、秒杀商品上架
【1】根据数据库start_time end_time查询需要上架的商品
******************************************************************************************
318、秒杀服务-幂等性保证
【1】分布式锁先锁住
【2】所的业务执行完成再释放
******************************************************************************************
319、查询秒杀商品
【1】for循环去拿商品
【2】获取后页面展示
******************************************************************************************
320、秒杀页面渲染
【1】thymeleaf的渲染与调整,参考性不大
******************************************************************************************
321、秒杀系统设计
【1】如何设计一个高并发的系统业务
【2】单一职责+独立部署、秒杀连接加密、库存预热+快速扣减、动静分离
【3】恶意请求拦截、流量错峰、限流&熔断&降级、队列削峰
******************************************************************************************
322、登录检查
【1】如果没登录点击秒杀,提示客户登录
******************************************************************************************
323、秒杀流程
【1】单独写一套描述的处理逻辑
******************************************************************************************
324、秒杀效果完成
【1】需要用到RMQ Redis技术
【2】恭喜秒杀成功,10s后跳转支付...

****************************************************************************************************************************************************************************

29、Sentinel
329、全服务引入Sentinel
 【1】配置sentinel
 【2】全服务配置
******************************************************************************************
330、流控模式&效果
【1】限流
【2】限流效果的定制
******************************************************************************************
331、熔断降级
【1】监控我们的服务
【2】这块在spring cloud都有说明
******************************************************************************************
332、自定义保护资源
【1】流控
******************************************************************************************
333、网关流控
【1】快速失败
【2】降级规则
【3】限流规则
******************************************************************************************
334、定制网关流控返回
【1】自定义响应数据和页面
******************************************************************************************
335、链路追踪-基本概念与整合
【1】每一个请求的追踪信息
******************************************************************************************
336、整合Zipkin效果
【1】导入Zipkin的依赖
【2】使用docker 安装zipkin
【3】配置properties里zipkin信息
******************************************************************************************
337、zipkin界面分析
【1】网络传输的可视化
******************************************************************************************
338、分布式高级篇总结
【1】拆分了多个微服务
【2】spring cloud的相关组件fegin
【3】幂等性
【4】分布式事务
【5】ES
【6】异步&线程池
【7】单点登录springsession与社交登录
【8】商城业务&RMQ 应用的解耦
【9】支付
【10】定时任务与任务调度
【11】spring cloud的组件掌握
【12】sentinel sleuth+zipkin
【13】缓存、异步、队排好

****************************************************************************************************************************************************************************

31、k8s(代码少了,运维多了)
340、k8s概述
【1】Kubernetes 简称 k8s。是用于自动部署,扩展和管理容器化应用程序的开源系统。
【2】相关资料
中文官网:https://kubernetes.io/zh/
中文社区:https://www.kubernetes.org.cn/
官方文档:https://kubernetes.io/zh/docs/home/
社区文档:http://docs.kubernetes.org.cn/
【3】传统的部署和迁移很困难
【4】虚拟化技术可以让部署迁移简单
【5】容器化时代:docker 镜像可以运行任何安装docker的环境中。
容器启动也快。
【6】但是容器的管理也比较麻烦,怎么管理呢?就需要k8s
【7】服务发现和负载均衡、存储编排、自动部署和回滚、自动二进制打包、自我修复、密匙与配置管理
【8】持续继承CI、交付和部署CI/CD
【9】k8s只是部署和管理集群,别的不干
******************************************************************************************
341、k8s架构与核心概念
【1】Master(主节点)主要管理node!!!!!!
【2】Nodexxx 具有docker和k8s 这个是来负责实际部署的
【3】通过API管理Master来操作具体节点
【4】主节点里面:kube-apiserver、kube-scheduler、kube-controller-manager、
etcd类似于mysql存一些数据用的。
【5】Node !!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
kubelet 每个节点运行的代理,它保证容器都运行在pod中
docker是1个容器1个容器。而一个pod可以容纳1个或多个容器。
kubelet 负责维护容器的生命周期,同时也负责Volume和网络的管理。
**************************
kube-proxy:网络相关的
**************************
容器运行环境 Container Runtime
【6】一个pod是共享一个网络的
【7】Service:定义一组 Pod 的访问策略(多个pod可以组合成一个service)
【8】Namespace:命名空间,逻辑隔离
******************************************************************************************
342、集群搭建-环境准备
【1】kubeadm
【2】需要外网环境、禁止swap分区
【3】在所有节点上安装 Docker 和 kubeadm!!!!!!!!!!
【4】Dashboard web页面
【5】192.168.0.205  206 207三台服务器   配置vi /etc/sysconfig/network-scripts/ifcfg-enp0s3  修改IP地址
******************************************************************************************
343、创建三个虚拟机
【1】修改hostname
vim /etc/hostname
【2】再多的修饰不如IP地址直接
【3】还好我提前搞好了,牛批
******************************************************************************************
344、NAT网络和前置配置
【1】连接网络 桥接网卡
【2】网络里刷新下mac地址
【3】全部关闭防火墙 systemctl status firewalld
【4】关闭 selinux:
sed -i 's/enforcing/disabled/' /etc/selinux/config
setenforce 0
查看关闭情况 cat /etc/selinux/config
【5】关闭 swap:
swapoff -a 临时
sed -ri 's/.*swap.*/#&/' /etc/fstab 永久
free -g 验证,swap 必须为 0;
【6】修改每一个主机的hosts文件
vim /etc/hosts
192.168.0.205 192-168-0-205
192.168.0.206 192-168-0-206
192.168.0.207 192-168-0-207
【7】将桥接的 IPv4 流量传递到 iptables 的链:
将桥接的 IPv4 流量传递到 iptables 的链:
cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system  系统应用此规则
******************************************************************************************
345、所有节点安装 Docker、kubeadm、kubelet、kubectl
【1】卸载系统之前的 docker
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine这个必须执行:sudo rm /usr/bin/docker
【2】安装 Docker-CE
安装必须的依赖
sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
【3】设置 docker repo 的 yum 位置
sudo yum-config-manager \ --add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
【4】安装 docker,以及 docker-cli
sudo yum install -y docker-ce docker-ce-cli containerd.io
【5】配置 docker 加速
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://vtaihzzp.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
【6】启动 docker & 设置 docker 开机自启
systemctl enable docker
【7】添加阿里云 yum 源
cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
【8】安装 kubeadm,kubelet 和 kubectl
yum list|grep kube
yum install -y kubelet-1.17.3 kubeadm-1.17.3 kubectl-1.17.3
systemctl enable kubelet  开机启动
systemctl start kubelet 启动
systemctl status kubelet 查看启动状态(这里启动不起来正常的)
******************************************************************************************
346、集群安装完成
【1】先把k8s文件夹拷贝到root目录。
chmod 755 master_images.sh
./master_images.sh
docker images可以查看下载的镜像
【2】master 节点初始化,被执行,先yum -y remove kubelet    yum install -y kubelet-1.17.3 kubeadm-1.17.3 kubectl-1.17.3
kubeadm init \
--apiserver-advertise-address=192.168.0.205 \
--image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \
--kubernetes-version v1.17.3 \
--service-cidr=10.96.0.0/16 \
--pod-network-cidr=10.244.0.0/16
******************************************
如果执行报错 执行kubeadm reset,然后再执行上方命令
*******************************************
版本报错  三台机器都要执行!!!!!!!!!!!!!!!!!!!!
yum -y remove kubelet
yum install -y kubelet-1.17.3 kubeadm-1.17.3 kubectl-1.17.3
然后再执行上方命令,成就感一下子就来了!!!!!!啧啧啧
*******************************************第一个命令返回的信息如下
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config    有个问号需要打yes回车
sudo chown $(id -u):$(id -g) $HOME/.kube/config
*******************************************
kubeadm join 192.168.0.205:6443 --token 3hx0pe.po2qkk71vgy3hzi5 \
    --discovery-token-ca-cert-hash sha256:22dafc23e2e5c879ea195d63d3137ccf62efd4070c3820e43c6bcd2d6d5daa6a
一般两个小时内有效。
*******************************************
部署一个网络!!!!!!!!!!!!!!!!!!!!!!!也是在给定的k8s文件里
kubectl apply -f kube-flannel.yml
*******************************************
kubectl get ns
kubectl get pods --all-namespaces
*******************************************
kubectl get nodes
【3】Node节点的添加
kubeadm join 192.168.0.205:6443 --token 3hx0pe.po2qkk71vgy3hzi5 \
    --discovery-token-ca-cert-hash sha256:22dafc23e2e5c879ea195d63d3137ccf62efd4070c3820e43c6bcd2d6d5daa6a
两个节点都执行,成功后
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.如果报错 The HTTP call equal to 'curl -sSL http://localhost:10248/healthz' failed with error: Get "http://localhost:10248/healthz": dial tcp 127.0.0.1:10248: connect: connection refused.
kubeadm reset
vim /etc/docker/daemon.json
{
  "registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"],
  "exec-opts": ["native.cgroupdriver=systemd"]
}
systemctl daemon-reload
systemctl restart docker
【4】看下节点启动详细信息
watch kubectl get pod -n kube-system -o wide
kubectl describe po coredns-7f9c544f75-8z7jx -n kube-system|less
*******************************************
改变kube-flannel.yml内容20230914百度网盘可以查询到
执行  kubectl apply -f kube-flannel.yml
再次运行 kubectl  get pods -n kube-system 查看 kube-flannel网络插件状态,如下状态即为成功。
稍等片刻 再次运行 kubectl  get pods -n kube-system   会发现coredns 正常
最终让每个节点都是ready状态
*******************************************
【5】至此整个集群就搭建成功了!!!!!!!!!!!!
******************************************************************************************
347、基本操作体验
【1】创建实例
kubectl create deployment tomcat6 --image=tomcat:6.0.53-jre8
kubectl get pods -o wide 创建后查看情况
kubectl get all # 查看所有资源情况
*******************************
容灾恢复
【2】暴露 nginx 访问
kubectl expose deployment tomcat6 --port=80 --target-port=8080 --type=NodePort
Pod 的 80 映射容器的 8080;service 会代理 Pod 的 80
kubectl get service
kubectl get service -o wide
http://192.168.0.205:31089/  访问查看后的端口即可访问tomcat
【3】动态扩容测试
kubectl get deployment
应用升级 kubectl set image (--help 查看帮助)
扩容: kubectl scale --replicas=3 deployment tomcat6
扩容了多份,所有无论访问哪个 node 的指定端口,都可以访问到 tomcat6
kubectl get pods -o wide  可以看到是三份
kubectl get service -o wide
【4】缩容
kubectl scale --replicas=1 deployment tomcat6
【5】删除
kubectl get all
kubectl delete deploy/nginx
kubectl delete deployment.apps/tomcat6
kubectl delete service/nginx-service
kubectl delete service/tomcat6
【6】流程;创建 deployment 会管理 replicas,replicas 控制 pod 数量,
有 pod 故障会自动拉起新的 pod
******************************************************************************************
348、k8s yaml&基本使用
【1】kubectl apply -f tomcat6.yaml
【2】yaml能替换超长的命令
【3】service pod container 三大资源类型
【4】yaml !!!!!!!!!!!!!!!!!!!!!!!!
******************************************************************************************
349、Pod Service...概念
【1】最小的部署单元Pod 
【2】控制器可以管理多个pod
【3】一个Service包含多个pod,service是对pod的负载均衡
【4】labelsSelector
******************************************************************************************
350、Ingress
【1】得到yaml模板
kubectl create deployment tomcat6 --image=tomcat:6.0.53-jre8 --dry-run -o yaml > tomcat6-deployment.yaml
*****************************
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: tomcat6
  name: tomcat6
spec:
  replicas: 3
  selector:
    matchLabels:
      app: tomcat6
  template:
    metadata:
      labels:
        app: tomcat6
    spec:
      containers:
      - image: tomcat:6.0.53-jre8
        name: tomcat
*****************************
kubectl apply -f tomcat6-deployment.yaml
*****************************
kubectl expose deployment tomcat6 --port=80 --target-port=8080 --type=NodePort --dry-run -o yaml
*****************************
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: tomcat6
  name: tomcat6
spec:
  replicas: 3
  selector:
    matchLabels:
      app: tomcat6
  template:
    metadata:
      labels:
        app: tomcat6
    spec:
      containers:
      - image: tomcat:6.0.53-jre8
        name: tomcat
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: tomcat6
  name: tomcat6
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: tomcat6
  type: NodePort
*****************************
kubectl delete deployment.apps/tomcat6  删除旧的部署
kubectl get all 查看删除后的状态
*****************************
kubectl apply -f tomcat6-deployment.yaml
提示两个:deployment.apps/tomcat6 created
service/tomcat6 created
*****************************
【2】Ingress解决暴露服务的痛点
Ingress可以管理多个Service,Ingress以域名的形式
cd k8s
kubectl apply -f ingress-controller.yaml  重点
*****************************
kubectl get pods --all-namespaces -o wide
*****************************
kubectl describe pod nginx-ingress-controller-clpml -n ingress-nginx
kubectl describe pod nginx-ingress-controller-wcd98 -n ingress-nginx
*****************************
kubectl logs nginx-ingress-controller-clpml -n ingress-nginx
kubectl logs nginx-ingress-controller-wcd98 -n ingress-nginx
发现是80端口占用的问题!!!!!!!!!!!!!!!!!
*****************************
删除pod!!!!!!!!!!!!!!!!!!
kubectl get deployment -n ingress-nginx 如果存在先删除部署
kubectl delete pod <podname> -n <namespace> 
到此终于自己解决了CrashLoopBackOff的问题!!!!!!!!!!!
*****************************
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: web
spec:
  rules:
  - host: example.atguigu.com     注意同步配置hosts的域名
    http:
      paths:
        - backend:
            serviceName: tomcat6
            servicePort: 80
注意格式 空格个数难顶!!!!!!!!!!!!!!!!!!!!
*****************************
http://example.atguigu.com:32081/  最后实现的就是这个效果也能访问
这个域名可以访问三台机器,即使有一台宕机了,其他两台也可以正常使用。
大功告成也!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

****************************************************************************************************************************************************************************

32、kubesphere
351、前置环境
【1】在k8s有kubernetes-dashboard.yaml
【2】kubesphere打通全部devops策略,以此为例!!!!!!!!!!!
【3】安装helm(master节点执行)
curl -L https://git.io/get_helm.sh | bash
百度网盘找到  k8s helm-v2.16.3-linux-amd64.tar
tar -zxvf helm-v2.16.3-linux-amd64.tar   解压
mv linux-amd64/helm /usr/local/bin/helm  移动到bin目录
helm version  查看版本
【4】安装 Tiller(master 执行)尼玛 找到一个万能的
#创建授权用户
[root@master ~]# vim tiller-rbac.yaml   
apiVersion: v1
kind: ServiceAccount
metadata:
  name: tiller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: tiller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: tiller
    namespace: kube-system
****************************************************************
[root@master ~]# kubectl apply -f tiller-rbac.yaml
[root@master ~]# helm init --service-account=tiller
****************************************************************
单独安装tiller吧 emmm
helm init --service-account tiller --upgrade --tiller-image=registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.16.3
#若您已经在k8s部署了tiller则只需要执行
helm init  --client-only
****************************************************************
可能报错:
helm init --service-account=tiller --tiller-image=jessestuart/tiller:v2.16.3 --history-max 300 --stable-repo-url https://charts.helm.sh/stable
[root@master ~]# kubectl get pod -n kube-system | grep tiller
[root@master ~]# kubectl edit pod tiller-deploy-8557598fbc-tvfsj -n kube-system
//编辑 pod 的 yaml 文件,将其使用的镜像改为国内阿里云的,默认是 Google 的镜像,下载不下来
//修改 spec 字段的 image 指定的镜像如下:
    image: gcr.io/kubernetes-helm/tiller:v2.14.3
//修改如下:
    image: registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.16.3
//修改后,保存退出即可,它会去自动下载新镜像(如果没有自动下载,就想办法吧,比如说在 tiller 容器所在的节点手动下载下来镜像,然后重启该节点的 kubelet,或重启该容器)
[root@master ~]# kubectl get pod -n kube-system | grep tiller
//只要保证 tiller 的 pod 正常运行即可
tiller-deploy-8557598fbc-m986t   1/1     Running   0          7m54s

helm version  查看版本,确保两个版本匹配!!!!!!!!!!!!!!!!!!!!!
****************************************************************
【5】配置 helm 仓库
[root@master ~]# helm repo list      //查看其仓库信息
NAME  	URL                                             
stable	https://kubernetes-charts.storage.googleapis.com
//如上,默认是 Google,在国外,速度特别慢
local 	http://127.0.0.1:8879/charts    
//执行下面命令,更改为国内阿里云的仓库
[root@master ~]# helm repo add stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
[root@master ~]# helm repo list      //再次查看,可以发现更改生效了
NAME  	URL                                                   
stable	https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
local 	http://127.0.0.1:8879/charts        
[root@master ~]# helm repo update    //更新一下 helm 仓库
[root@master ~]# helm version        //查看 helm 版本信息,必须保证可以查看出来 client 和 server,才可正常使用 helm
Client: &version.Version{SemVer:"v2.14.3", GitCommit:"0e7f3b6637f7af8fcfddb3d2941fcc7cbebb0085", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.14.3", GitCommit:"0e7f3b6637f7af8fcfddb3d2941fcc7cbebb0085", GitTreeState:"clean"}
 【6】测试 helm 是否可以正常使用
 [root@master ~]# helm search mysql      //搜索 MySQL
//查看到的是 charts 包文件,查出来的版本是 helm 的 Charts 包的版本
[root@master ~]# helm inspect stable/mysql    //查看其详细信息
[root@master ~]# helm fetch stable/mysql      //下载搜索到的包到本地
[root@master templates]# helm install stable/mysql     //在线安装这个 MySQL
【7】配置PV
kubectl get node -o wide
kubectl describe node 192-168-0-205|grep Taint
如果有污点去掉:kubectl taint nodes 192-168-0-205 node-role.kubernetes.io/master:NoSchedule-
kubectl create ns openebs
helm install --namespace openebs --name openebs stable/openebs --version 1.5.0
报错!!!!!!!!!!
helm repo add stable http://mirror.azure.cn/kubernetes/charts/   !!!!!!!!!!!!!!!
helm repo update 
helm install --namespace openebs --name openebs stable/openebs --version 1.5.0
kubectl get sc   (需要等三分钟的)!!!!!!!!!!!!!!!!!
【8】将 openebs-hostpath 设置为 默认的 StorageClass:
kubectl patch storageclass openebs-hostpath -p \
'{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
【9】污点还原!!!!!!!!!!!!!!!!!!
kubectl taint nodes 192-168-0-205 node-role.kubernetes.io=master:NoSchedule
【10】pv pvc
****************************************************************
352、最小化安装完成
【1】主要是xxx.yaml文件
kubectl apply -f kubesphere-minimal.yaml  内容如下方
****************************************************************
---
apiVersion: v1
kind: Namespace
metadata:
  name: kubesphere-system

---
apiVersion: v1
data:
  ks-config.yaml: |
    ---
    persistence:
      storageClass: ""
    etcd:
      monitoring: False
      endpointIps: 192.168.0.7,192.168.0.8,192.168.0.9
      port: 2379
      tlsEnable: True
    common:
      mysqlVolumeSize: 20Gi
      minioVolumeSize: 20Gi
      etcdVolumeSize: 20Gi
      openldapVolumeSize: 2Gi
      redisVolumSize: 2Gi
    metrics_server:
      enabled: False
    console:
      enableMultiLogin: False  # enable/disable multi login
      port: 30880
    monitoring:
      prometheusReplicas: 1
      prometheusMemoryRequest: 400Mi
      prometheusVolumeSize: 20Gi
      grafana:
        enabled: False
    logging:
      enabled: False
      elasticsearchMasterReplicas: 1
      elasticsearchDataReplicas: 1
      logsidecarReplicas: 2
      elasticsearchMasterVolumeSize: 4Gi
      elasticsearchDataVolumeSize: 20Gi
      logMaxAge: 7
      elkPrefix: logstash
      containersLogMountedPath: ""
      kibana:
        enabled: False
    openpitrix:
      enabled: False
    devops:
      enabled: False
      jenkinsMemoryLim: 2Gi
      jenkinsMemoryReq: 1500Mi
      jenkinsVolumeSize: 8Gi
      jenkinsJavaOpts_Xms: 512m
      jenkinsJavaOpts_Xmx: 512m
      jenkinsJavaOpts_MaxRAM: 2g
      sonarqube:
        enabled: False
        postgresqlVolumeSize: 8Gi
    servicemesh:
      enabled: False
    notification:
      enabled: False
    alerting:
      enabled: False
kind: ConfigMap
metadata:
  name: ks-installer
  namespace: kubesphere-system

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: ks-installer
  namespace: kubesphere-system

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  creationTimestamp: null
  name: ks-installer
rules:
- apiGroups:
  - ""
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - apps
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - extensions
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - batch
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - rbac.authorization.k8s.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - apiregistration.k8s.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - apiextensions.k8s.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - tenant.kubesphere.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - certificates.k8s.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - devops.kubesphere.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - monitoring.coreos.com
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - logging.kubesphere.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - jaegertracing.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - storage.k8s.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - admissionregistration.k8s.io
  resources:
  - '*'
  verbs:
  - '*'

---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: ks-installer
subjects:
- kind: ServiceAccount
  name: ks-installer
  namespace: kubesphere-system
roleRef:
  kind: ClusterRole
  name: ks-installer
  apiGroup: rbac.authorization.k8s.io

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ks-installer
  namespace: kubesphere-system
  labels:
    app: ks-install
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ks-install
  template:
    metadata:
      labels:
        app: ks-install
    spec:
      serviceAccountName: ks-installer
      containers:
      - name: installer
        image: kubesphere/ks-installer:v2.1.1
        imagePullPolicy: "Always"
【2】日志,等待10分钟左右拉取镜像才能看到日志!!!!
kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l \
app=ks-install -o jsonpath='{.items[0].metadata.name}') -f
**********************************
#####################################################
###              Welcome to KubeSphere!           ###
#####################################################

Console: http://192.168.0.205:30880
Account: admin
Password: P@88w0rd
**********************************
kubectl get pods --all-namespaces  等10分钟左右,所有的pods都running状态
访问这个地址:
http://192.168.0.205:30880
卧槽 牛批 卧槽 牛批 卧槽 牛批 卧槽 牛批 卧槽 牛批 卧槽 牛批 卧槽 牛批 卧槽 牛批 
卧槽 牛批 卧槽 牛批!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
********************************************************************************************************************************
********************************************************************************************************************************
********************************************************************************************************************************
353、定制化安装&界面概述!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
【1】开启DevOps系统
【2】日志和微服务治理
首先两个node节点服务器内存调整到12G左右的内存。
kubectl get nodes
kubectl get pod --all-namespaces(注意解决80端口占用问题)
【3】kubectl edit cm -n kubesphere-system ks-installer
修改的地方:
devops:
      enabled: True
**************************
sonarqube:
        enabled: True
**************************
 notification:
      enabled: True
    alerting:
      enabled: True
**************************
kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l \
app=ks-install -o jsonpath='{.items[0].metadata.name}') -f
#####################################################
#####################################################
#####################################################
大概等待20分钟左右!!!!!!!!!!!!!!!!!!!!
#####################################################
###              Welcome to KubeSphere!           ###
#####################################################

Console: http://192.168.0.205:30880
Account: admin
Password: P@88w0rd

NOTES:
  1. After logging into the console, please check the
     monitoring status of service components in
     the "Cluster Status". If the service is not
     ready, please wait patiently. You can start
     to use when all components are ready.
  2. Please modify the default password after login.
#####################################################
**************************
【4】企业空间、项目管理、
可能原因k8s初始化cluster-cidr和service-cluster-ip-range子网划分冲突
**************************
(原    --apiserver-advertise-address 10.192.30.20  --service-cidr 10.245.0.0/12    --pod-network-cidr 10.244.0.0/16)
修改/etc/kubernetes/manifests/kube-controller-manager.yaml
- --cluster-cidr=192.168.0.0/255
- --service-cluster-ip-range=192.168.0.0/255
 #修改此处 自己的ip地址范围
**************************
别说还挺好用!!!!!!!!!!!!!!!靠自己的觉悟
kubectl logs -f --tail 200 -n  kube-system 【pod-name】
kubectl apply -f kubesphere-minimal.yaml  重启后还的安装
kubectl logs -f --tail 200 -n  kube-system kube-controller-manager-192-168-0-205
**************************
kubectl logs -f --tail 200 -n  【namespace-name】 【pod-name】 日志有用呀
**************************
kubectl logs -f --tail 200 -n kubesphere-devops-system ks-sonarqube-sonarqube-f68dd5ff5-97527 
【5】重新安装kubesphere
kubectl apply -f kubesphere-minimal.yaml 
**************************
kubectl delete ns kubesphere-devops-system --force --grace-period=0
kubectl logs -f --tail 200 -n  【namespace-name】 【pod-name】
kubectl logs -f --tail 200 -n  kubesphere-system ks-apigateway-564b697958-dqxl7
**************************
kubectl get namespace kubesphere-devops-system -o json \
            | tr -d "\n" | sed "s/\"finalizers\": \[[^]]\+\]/\"finalizers\": []/" \
            | kubectl replace --raw /api/v1/namespaces/kubesphere-devops-system/finalize -f -
卧槽 牛批的删除方法!!!!!!!!!!!!!!!!!改两个地方
kubectl get namespace kubesphere-system -o json \
            | tr -d "\n" | sed "s/\"finalizers\": \[[^]]\+\]/\"finalizers\": []/" \
            | kubectl replace --raw /api/v1/namespaces/kubesphere-system/finalize -f -
【6】如果pod镜像拉取失败,可以尝试删除后重新拉取
kubectl logs -f --tail 200 -n  【namespace-name】 【pod-name】 日志有用呀
kubectl delete pod <podname> -n <namespace>   删除pod
**********************************
也很重要 ,对于处理有拉取问题的pods!!!!!!!!!!!!!!!!!!!!!!!
kubectl delete --all pods --namespace=foo   批量删除命名空间里的pods
**********************************
Account: admin
Password: P@88w0rd
**********************************查看docker配置!!!!!!!!!!!!!
vim /etc/docker/daemon.json
**********************************
****************************************************************
354、进阶-建立多租户系统
【1】集群、企业空间、项目和DevOps
【2】创建角色、账号
hr增删改查用户,角色也可以维护
work-sapce-manager:企业空间管理员
work-sapce-admin:企业空间管理角色
project-admin:项目管理人员
project-common:项目执行人员
****************************************************************
355、创建WordPress应用-密匙
【1】mysql+wordpress  持久化存储都是用pvc
【2】pvc:PersistentVolumenClaim
【3】创建秘钥:
创建MySQL秘钥:123456  可以参考docker-mysql创建部分
WordPress秘钥:123456
【4】存储卷 安装默认10G创建即可
http://192.168.0.205:30880/projects/mall/volumes
****************************************************************
356、创建WordPress应用-容器
【1】创建应用 mysql  有状态服务
【2】跟着老师界面化操作应用创建
****************************************************************
357、外网访问
【1】http://192.168.0.205:30368
****************************************************************
358、什么是devops
【1】dev开发  ops运维
【2】开发 运维 质量保障
【3】突出的是开发人员和运维人员的合作
【4】CI&CD
【5】持续集成:CI ContinuousIntegration
全面化的自动化测试...
灵活的基础设施、容器、虚拟机
版本控制工具git!!!! cvs svn
自动化构建和软件发布流程的工具:jenkins
【6】持续交付:CD ContinuousDelivery
快速发布...
编码、测试、上线、交付
高质量的软件发布标准
整个交付进度可视化
先进的团队协作方式
【7】持续部署:CD ContinuousDeployment
【8】全流程监视工具:
Collaborate!!!!!!!!!!!!!!!!!!!!
JIRA(查看进度)/国内是禅道
bulid!!!!!!!!!!!!!!!!!!!!
版本控制:git
持续集成:jenkins
构建工具:maven
Test!!!!!!!!!!!!!!!!!!!!
Jmeter
Deploy!!!!!!!!!!!!!!!!!!!!
ssh
vagrant
docker
Run!!!!!!!!!!!!!!!!!!!!
阿里云  kubernetes
es kibana
****************************************************************
359、流水线-创建凭证
【1】jenkins基于springboot项目构建流水线
【2】流水线:检查SCM—>单元测试—>SONARQUBE分析—>构建与上传快照
—>拉取最新镜像—>人工确认是否部署到线上—>拉取Tag—>部署上线—>成功
【3】一共有三个凭证
微信都收藏了,记得查看,记得墙!!!!!!!!
【4】找到sonarqube 暴露的端口
kubesphere-devops-system       ks-sonarqube-sonarqube             
NodePort    10.96.92.48     <none>        9000:30163/TCP           13h
账号密码是:admin admin
点击生成token
**************************
Provide a token
mall-analyze: e50167e4926213f19464070ab10b74f640ab90ed
【5】至此四个凭证都OK了  11分01秒
修改github的Jenkinsfile-online内容,还得墙
environment {
        DOCKER_CREDENTIAL_ID = 'dockerhub-id'
        GITHUB_CREDENTIAL_ID = 'github-id'
        KUBECONFIG_CREDENTIAL_ID = 'demo-kubeconfig'
        REGISTRY = 'docker.io'
        DOCKERHUB_NAMESPACE = 'yuebuqun163'
        GITHUB_ACCOUNT = 'yuebuqun163'
        APP_NAME = 'devops-java-sample'
        SONAR_CREDENTIAL_ID = 'sonar-qube'
    }
****************************************************************
360、CICD完整体验(需要就再看下这一集就OK)!!!!
【1】创建流水线
【2】内网穿透的推送,github的配置Webhooks ,web钩子 回调,只要github有代码提交,
就通知jenkins
【3】代码都在src里面
【4】流水线可以人工干预
【5】智能+人工  哈哈哈哈
【6】可以创建多个流水线从github拉取代码,起飞,拉取git就是内网,没有网络问题

****************************************************************************************************************************************************************************

33、集群
361、集群常见的基本形式
【1】单点机器可能会出现问题
【2】集群的目标:
高可用、突破数据量的限制、数据备份容灾、压力分担
【3】集群的基本形式
主从模式:主从复制、主从调度
分片式:数据分片存储、片区之间备份
选主式:容灾选主、调度选主
******************************************************************************************
362、mysql常见的集群形式
【1】一主两从 Monitor(负责IP的飘移)
【2】主从复制、双主复制
******************************************************************************************
363、主从同步
【1】主机 cd/mydata/mysql
docker run -p 3307:3306 --name mysql-master \
 -v /mydata/mysql/master/log:/var/log/mysql \
 -v /mydata/mysql/master/data:/var/lib/mysql \
 -v /mydata/mysql/master/conf:/etc/mysql \
 -e MYSQL_ROOT_PASSWORD=root \
 -d mysql:5.7
 ************************************
 vim /mydata/mysql/master/conf/my.cnf
************************************
server_id=1
log-bin=mysql-bin
read-only=0
binlog-do-db=gulimall_ums
binlog-do-db=gulimall_pms
binlog-do-db=gulimall_oms
binlog-do-db=gulimall_sms
binlog-do-db=gulimall_wms
binlog-do-db=gulimall_admin
replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=information_schema
replicate-ignore-db=performance_schema
************************************
重启master
【2】创建从机
docker run -p 3317:3306 --name mysql-slaver-01 \
 -v /mydata/mysql/slaver/log:/var/log/mysql \
 -v /mydata/mysql/slaver/data:/var/lib/mysql \
 -v /mydata/mysql/slaver/conf:/etc/mysql \
 -e MYSQL_ROOT_PASSWORD=root \
 -d mysql:5.7
****************************************
vim /mydata/mysql/slaver/conf/my.cnf
【3】docker restart xxx1 xxx2
【4】为 master 授权用户来他的同步数据
【5】配置 slaver 同步 master 数据
******************************************************************************************
364、ShardingSphere概述
【1】Shading JDBC
【2】Shading Proxy
******************************************************************************************
365、分库分表
【1】因为主从复制,检索性能下降
【2】sharding-proxy实现分库分表
【3】shardingRule 规则的指定
******************************************************************************************
366、redis集群基本原理
【1】一致性hash
******************************************************************************************
367、redis集群搭建
【1】3主3从方式,为了同步备份,主进行slot数据分片
【2】启动后是3M  3S的redis集群
【3】查询数据计算槽slot
******************************************************************************************
368、ES集群
【1】多个实例,分片存储
【2】主节点、候选主节点
【3】脑裂问题的解决方案:角色分离、减少误判、选举触发
******************************************************************************************
369、ES集群搭建
【1】创建网络
【2】配置节点,启动ES
【3】master和node
******************************************************************************************
370、RMQ集群搭建
【1】镜像模式
【2】依次启动多个RMQ 15673 15674 15675

****************************************************************************************************************************************************************************

34、部署
371、如何在k8s上部署有状态应用
【1】ConfigMap
【2】PVC
******************************************************************************************
372、k8s部署mysql
【1】用kubesphere部署
【2】创建有状态服务应用,加载存储卷
******************************************************************************************
373、k8s部署redis
【1】有状态服务!!!!!!!!!!!!!
【2】redis.conf  redis-pvc
******************************************************************************************
374、k8s部署es和kibana
【1】es的配置 es-pvc
【2】kibana
******************************************************************************************
375、k8s部署RMQ
【1】rmq.conf
【2】rmq.pvc
******************************************************************************************
376、k8s部署Nacos
【1】nacos.conf
【2】nacos.pvc
******************************************************************************************
377、k8s部署zipkin
【1】zipkin链路追踪的部署
******************************************************************************************
378、k8s部署Sentinel
【1】使用别人做好的镜像
******************************************************************************************
379、k8s部署应用流程
【1】Docker镜像
【2】Docker部署文件
【3】DockerFile
【4】Docker安装DockerFile将项目制作成镜像(这需要手动部署)
【5】而jenkins可以实现自动打包部署
******************************************************************************************
380、生产环境配置抽取
【1】spring.profiles.active=xxx 激活配置文件
【2】配置线上地址
******************************************************************************************
381、创建微服务的DockerFile
【1】示例
FROM java8
EXPOSE 8080

VOLUME /tmp
ADD xxx.jar
RUN bash -c touch/xxx.jar
ENTRYPOINT ["java","-jar","xxx.jar"]
**************************************
【2】docker build -f DockerFile -t docker.io/wdfgdzx/admin:V1.0 .
【3】执行后就能看到镜像
【4】就能用docker run xxx执行
【5】每一个微服务下面放一个DockerFile
******************************************************************************************
382、k8s部署描述文件
【1】每一个微服务都应该有一个部署文件
【2】xxx-depoly.yaml,就是kubectl apply -f xxx的内容
apiVersion: apps/v1
kind: Deployment 
metadata:
  name: product
  namespace: ms 
spec:
  replicas: 2
  selector:
    matchLabels:
      project: ms
      app: product
  template:
    metadata:
      labels:
        project: ms 
        app: product
    spec:
      imagePullSecrets:
      - name: registry-pull-secret
      containers:
      - name: product
        image: 192.168.31.70/microservice/product:2019-07-10-21-34-34
        imagePullPolicy: Always
        ports:
          - protocol: TCP
            containerPort: 8010 
******************************************************************************************
383、理解targetPort、Port、NodePort
【1】targetPort 容器暴露给pod的端口
【2】Port , 整个service的服务器端口(里面包含多个pods)
【3】NodePort:31773 能映射多个service端口,外部访问用的
节点端口对外暴露的,是唯一的,不能重复的!!!!!
【4】targetPort  Port暴露的端口是可以重复的。

****************************************************************************************************************************************************************************

35、流水线 
384、gitee拉取代码
【1】 label:maven
【2】拉取代码 从git拉取代码
******************************************************************************************
385、参数化构建&环境变量
【1】编辑流水线,sh echo $PROJECT_VERSION
【2】环境变量也可以动态配置
******************************************************************************************
386、Sonar代码质量分析
【1】还是要去阿里云拉取镜像
【2】下载日志查看
******************************************************************************************
387、调试完成
【1】也可以去码云拉取
【2】12.28行代码、9个bug、26个漏洞、容易出错812行...
******************************************************************************************
388、构建和推送镜像
【1】按照指定的docker账号密码登录到docker
【2】然后把本地镜像推送到docker
【3】最终镜像就能推送到docker hub
******************************************************************************************
389、流水线编写完成
【1】k8s部署git根目录
【2】复制到JAVA项目的yaml里面

****************************************************************************************************************************************************************************

36、部署-2 
390、移植数据库
【1】把数据导入到docker mysql...
******************************************************************************************
391、流水线细节优化&解决DOM
【1】用码云的更方便
【2】开启浅克隆
******************************************************************************************
392、流水线部署所有的微服务
【1】构建镜像---部署到k8s---发布版本
******************************************************************************************
393、Docker镜像操作
【1】docker login -u xxx  登录docker hub
【2】国外的镜像还有点慢的
******************************************************************************************
394、整合阿里云的镜像仓库
【1】阿里云创建镜像仓库
https://cr.console.aliyun.com/cn-hangzhou/instance/repositories
【2】登录阿里云Docker Registry
$ docker login --username=wdfgdzx@163.com registry.cn-hangzhou.aliyuncs.com
【3】从Registry中拉取镜像
$ docker pull registry.cn-hangzhou.aliyuncs.com/wdfgdzx/wdfgdzx_aliyun:[镜像版本号]
【4】将镜像推送到Registry
$ docker login --username=wdf****@163.com registry.cn-hangzhou.aliyuncs.com
$ docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/wdfgdzx/wdfgdzx_aliyun:[镜像版本号]
$ docker push registry.cn-hangzhou.aliyuncs.com/wdfgdzx/wdfgdzx_aliyun:[镜像版本号]
亲测可以推送成功
******************************************************************************************
395、Jenkins修改阿里云镜像仓库
【1】创建阿里云的凭证
******************************************************************************************
396、部署gateway
【1】如果失败多刷几次网页
【2】访问节点端口
******************************************************************************************
397、部署auth-server
【1】访问出现404说明可以访问通
******************************************************************************************
398、部署cart
【1】用kubesphere直接部署即可
******************************************************************************************
399、商城系统上线
【1】访问到前端商城
【2】编辑规则,添加服务
******************************************************************************************
400、部署coupon
【1】优惠券
******************************************************************************************
401、部署完成&bug修改
【1】商品服务
【2】秒杀服务
【3】redis地址的更改
******************************************************************************************
402、修改为共有仓库
【1】阿里云修改为公开

****************************************************************************************************************************************************************************

source /etc/rc.d/rc.local 
学习必备的Linux启动nacos
******************************************************************************************
37、最终部署
403、第一次部署前置nginx
【1】创建阿里云docker仓库
******************************************************************************************
404、创建网关与应用路由
【1】nginx挂载页面资源的情况
******************************************************************************************
405、部署VUE项目
【1】dist文件复制
【2】打包成tar.gz
******************************************************************************************
406、部署admin-vue-app
【1】docker build xxx
******************************************************************************************
407、上线预警与监控
【1】在监控告警里添加告警策略(比如监控内存连续超过多少)
【2】告警就回以邮件的形式发送过去
******************************************************************************************
408、集群部署篇-总结
【1】k8s+kubesphere
【2】应用路由,ingress-controller
【3】配置中心
【4】devops 自动化构建
【5】可高用 主从 分片 选领导
【6】学无止境

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/588939.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【python】python标准化考试系统[单项选择题 简易版](源码)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

docker挂载数据卷-以nginx为例

目录 一、什么是数据卷 二、数据卷的作用 三、如何挂载数据卷 1、创建nginx容器挂载数据卷 2、查看数据卷 3、查看数据卷详情 4、尝试在宿主机修改数据卷 5、查看容器内对应的数据卷目录 6、 访问nginx查看效果 ​​​​​​​一、什么是数据卷 挂载数据卷本质上就是实…

基于springboot实现公司日常考勤系统项目【项目源码+论文说明】

基于springboot实现公司日常考勤系统演示 摘要 目前社会当中主要特征就是对于信息的传播比较快和信息内容的安全问题&#xff0c;原本进行办公的类型都耗费了很多的资源、传播的速度也是相对较慢、准确性不高等许多的不足。这个系统就是运用计算机软件来完成对于企业当中出勤率…

Unity3D初级实战项目之方块跑酷

目录 初始化项目开发环境初始化项目屏幕自适应 游戏UI界面元素布局开始界面UI角色选择&#xff08;商城&#xff09;界面UI游戏界面UI 地图生成算法之菱形布局Resources资源加载代码生成地图菱形布局 地图生成算法之墙壁边界菱形地图双排布局地图瓷砖颜色美化墙壁边界生成 地图…

git提交错了?别慌,直接删除提交记录

为什么要删除提交历史 前几天产品提了个很扯淡的需求&#xff0c;我在代码了进行了吐槽.... 要命的是我不下心进行了代码提交&#xff1a; 我们的远程仓库大家都能看见的 这要是被其他人发现就惨了&#xff01;当务之急&#xff0c;我必须立刻马上删除这一条提交记录&#xff…

菜鸡学习netty源码(一)——ServerBootStrap启动

1.概述 对于初学者而然,写一个netty本地进行测试的Server端和Client端,我们最先接触到的类就是ServerBootstrap和Bootstrap。这两个类都有一个公共的父类就是AbstractBootstrap. 那既然 ServerBootstrap和Bootstrap都有一个公共的分类,那就证明它们两个肯定有很多公共的职…

EMP.DLL是什么东西?游戏提示EMP.DLL文件缺失怎么解决

emp.dll文件是Windows操作系统中的一种动态链接库文件&#xff0c;它被设计为可以被多个程序共享使用的模块化文件。这种设计旨在提高系统效率&#xff0c;减少内存消耗&#xff0c;并简化软件的维护和更新。DLL文件通常包含了一系列相关的函数和变量&#xff0c;这些函数和变量…

全景剖析阿里云容器网络数据链路(七):Terway DataPath V2(Terway≥1.8.0)

作者&#xff1a;余凯 前言 近几年&#xff0c;企业基础设施云原生化的趋势越来越强烈&#xff0c;从最开始的IaaS化到现在的微服务化&#xff0c;客户的颗粒度精细化和可观测性的需求更加强烈。容器网络为了满足客户更高性能和更高的密度&#xff0c;也一直在高速的发展和演…

qt学习篇---界面按键关联(信号和槽)

目录 1.qt基础 2.做一个界面 创建project UI界面设计 信号和槽 1.控件改名字 2.什么是信号和槽 3.怎么关联信号和槽 自动关联 手动关联 1.qt基础 qt可移植性强&#xff0c;不久会用到MCU。很有意义学习 2.做一个界面 创建project 不要中文路径 选择QWidget .pro文件…

ASP.NET实验室预约系统的设计

摘 要 实验室预约系统的设计主要是基于B/S模型&#xff0c;在Windows系统下&#xff0c;运用ASP.NET平台和SQLServer2000数据库实现实验室预约功能。该设计主要实现了实验室的预约和管理功能。预约功能包括老师对实验室信息、实验项目和实验预约情况的查询以及对实验室的预约…

LeetCode 69—— x 的平方根

阅读目录 1. 题目2. 解题思路一3. 代码实现一4. 解题思路二5. 代码实现二 1. 题目 2. 解题思路一 二分查找法&#xff0c;对于整数 i ∈ [ 0 , x ] i \in [0,x] i∈[0,x]&#xff0c;我们判断 i 2 i^2 i2 和 x x x 的关系&#xff0c;然后找到最后一个平方小于等于 x x x …

向量语义学

书籍&#xff1a;Vector Semantics 作者&#xff1a;Andrs Kornai 出版&#xff1a;Springer Singapore 书籍下载-《向量语义学》本书通过提出一个以线性多面体术语表达的形式理论来弥合这一差距&#xff0c;该理论将字向量和概念结构进行了概括&#xff0c;将每个词典定义视…

45. UE5 RPG 使用元属性(Meta Attributes)以及使用Set by Caller修改伤害

在RPG游戏中&#xff0c;我们是不会直接修改生命值的属性&#xff0c;是因为在修改角色属性时&#xff0c;需要获取角色的属性并进行复杂的计算&#xff0c;所以&#xff0c;我们正常情况下使用元属性&#xff08;Meta Attributes&#xff09;作为计算的中间的媒。在服务器上先…

前端-React项目初始化

大家好我是苏麟 , 今天聊聊前端依赖 Ant Desgin Pro 快速初始化项目 . Ant Desgin Pro 官网 : 开始使用 - Ant Design Pro 初始化项目 找到文档->快速上手 脚手架命令 : # 使用 npm npm i ant-design/pro-cli -g创建项目命令 : pro create 项目名称 选择简单还是全量 : …

Python | Leetcode Python题解之第64题最小路径和

题目&#xff1a; 题解&#xff1a; class Solution:def minPathSum(self, grid: List[List[int]]) -> int:if not grid or not grid[0]:return 0rows, columns len(grid), len(grid[0])dp [[0] * columns for _ in range(rows)]dp[0][0] grid[0][0]for i in range(1, r…

五大开放式耳机推荐,选对耳机让运动更带感!

看似精彩的户外运动经历背后&#xff0c;其实是枯燥的体能运动和训练&#xff0c;以及独自长途和长时间旅行伴随的孤独感&#xff0c;而排解这些不良情绪的最佳方式就是音乐。如果你希望在运动、舒适、安全和音质之间获得一个最佳平衡&#xff0c;那相比入耳式耳机&#xff0c;…

71.网络游戏逆向分析与漏洞攻防-角色与怪物信息的更新-分析并利用角色与怪物创建的数据包

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果 现在的代码都是依据数据包来写的&#xff0c;如果看不懂代码&#xff0c;就说明没看懂数据包…

『项目整理』易CAR通项目说明文档-我的第一款APP

『项目整理』易CAR通项目说明文档-我的第一款APP 项目介绍功能介绍技术栈介绍实现效果如何运行备注 项目介绍 易CAR通项目是我的第一个Android项目。是一款结合了AR技术的模仿懂车帝的看车软件。因为是初学&#xff0c;所示实现的效果差强人意&#xff0c;很多的功能界面只实现…

文件批量高效管理,批量将PDF类型文件移动到指定文件夹里,实现文件高效管理

文件的管理与整理成为了我们生活中不可或缺的一部分。面对堆积如山的PDF文件&#xff0c;你是否也曾感到手足无措、焦头烂额&#xff1f;现在&#xff0c;有了我们的批量文件管理工具&#xff0c;PDF文件的管理将变得前所未有的高效与简单&#xff01; 首先&#xff0c;我们要…

对于Servlet项目无法显示css样式

有可能你在过滤器中拦截了.css文件&#xff0c;并且你设置了响应格式导致的&#xff0c;就比如我的项目如下图所示 删除servletResponse.setContentType("text/html; charsetUTF-8");即可
最新文章