知识点
    1, 代码编写技巧
    2, redis实现分布式锁

    1. 主要是依赖redis自身的原子操作。实现是通过向redis里面存入一个值
    2. 来代表加锁,如果存入成功则表示加锁成功,如果存入的时候值已经存在
    3. 就代表加锁失败。
    4. 解锁就是删除该值。
    5. 加锁的时候可以给值设置一个过期时间来防止死锁。
    1. 掌握Redisson编写分布式
    1、导包
    <dependency>
      <groupId>org.redisson</groupId>
      <artifactId>redisson-spring-boot-starter</artifactId>
      <version>3.14.0</version>
    </dependency>
    
    //通过redison客户端获取可重入锁对象可以存入对象id 
    //例如:"order:goods:id:"+op.getGoodsId()
    Rlock lock = redissonClient.getLock(key);
    //加锁
    boolean res = lock.tryLock(20,20,TimeUnit.SECONDS);
    //判断res加锁是否成功来执行业务操作
    (if){
        //判断成功进行操作
    }
    //解锁
    lock.unlock;
    

    2)理解分布式锁的实现方案

    方案有三种:数据库、Redis、Zookeeper
    •数据库
            实现简单,但是数据库性能存在瓶颈,不适合高并发场景。锁的失效时间难以控制,删除锁失败容易导致死锁(数据库加锁是通过字段来代表锁的,即这把锁没有过期时间,一旦解锁操作失败就会导致锁一直记录在数据库中,其他线程无法在获得到锁)。
        一般在分布式系统中使用这种机制实现分布式锁时,需要在业务中增加控制锁超时和充实的流程。
    •Redis
            性能好,实现起来方便。但是存在单点问题:指的是单master。就算是集群中,如果加锁成功后,锁从master复制到到保存的时候挂掉了,也是会出现同一个资源被多个client加锁的
    •Zookeeper分布式锁
            ZooKeeper是一个为分布式应用提供一致性服务的开源组件,它内部是一个分层的文件系统目录树结构,规定同一个目录下只能有一个唯一文件名。
    

    3) 能够说出redis实现分布式锁的流程

    具体加锁步骤可以如下:
    1. 准备向Redis里面存入一个值
    2. 判断如果该值存在就说明已经有其他线程加锁成功,现在不能存入只能等待或者加锁失败
    3. 如果该值不存在则当前线程存入成功(加锁成功)
    4. 对该值设置过期时间(锁可以在一定时间之后自动释放)
    

    3, RokcetMQ
    1)掌握springboot集成RocketMQ的方式

    1、导入依赖
    <dependency>
        <groupId>org.apache.rocketmq</groupId>
        <artifactId>rocketmq-spring-boot-starter</artifactId>
        <version>2.1.1</version>
    </dependency>
    2、配置连接生产者组
    3、注入模板对象RocketMQTemplate
    private RocketMQTemplate rocketMQTemplate;
    
    3、通过rocketMQTemplate.方法进行不同消息类型的发送
    
    4、编写消费消息的类,继承RocketMQListener<T>
    (1)类上加@Component
                        @RocketMQMessageListener(consumerGroup = "分组名称",
                                          topic = "主题名称",
                            selectorExpression = "order_pay")
    

    2)掌握在SpringBoot里面发送各种类型消息的语法
    1,同步消息

    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    1,发送同步消息
    @GetMapping("/send")
    public String sendMessage(String msg){
        //携带tag和key
      Message<String> message = MessageBuilder.withPayload(msg)
                              .setHeader("KEYS",UUID.randomUUID().toString())
                  .build();
      //发送消息
      rocketMQTemplate.send("msgTest:order_pay",message);
    }
    

    2,异步消息

    @GetMapping("/send2")
    public String sendMessage2 (String msg){
    
    }
    

    3)掌握消费者如何监听

    监听方式:消息重试、消息重头、死信队列
    消息重试:
            消费者(Consumer)消费消息失败后,要提供一种重试机制令消息再消费一次。RocketMQ会为每个消费组都设置一个Topic名称为“%RETRY%+consumerGroup”的重试队列,重试次数越多投递延时就越大。
    
    消息重投:
            生产者在发送消息时,同步消息失败会重投,异步消息失败会重试,oneway没有任何保证。消息重投保证消息尽可能发送成功、不丢失,但是可能会造成消息重复,消息重复再RocketMQ中是无法避免的问题。
    
    死信队列:
            死信队列用处处理无法被正常消费的消息。当一条消息初次消费失败,消息队列会自动进行消息重试,达到最大重试次数后若依然消费失败,则表明消费者在正常情况下无法争取的消费该消息,此时,消息队列不会立刻将消息丢弃,而是将其发送到该消费者对应的特殊队列中。
        这种无法被消费的消息称为死信消息,存储死信消息的队列叫做死信队列。在RocketMQ中,可以通过使用console控制台对死信队列中的消息进行重发来是的消费者实例再次进行消费。
    

    4)理解RocketMQ使用场景

    1、异步解耦
    2、分布式事务的数据一致性
    3、事务消息处理
    4、消息的顺序收发
    5、流量削峰
    6、大规模机器的缓存同步
    

    5) 理解消息中间件的特点

    1、能够保证严格的消息顺序
    2、提供丰富的消息拉取模式
    3、高效的订阅者水平扩展能力
    4、试试的消息订阅机制
    5、亿级消息堆积能力
    6、支持分布式事务
    

    6)理解消息可靠性传输的解决方案

            produce生产者端:不采用oneway发送消息,使用同步或者异步的方法,做好重试,但是重试的Message Key必须唯一。
            broker端:双主双从架构,NamerServer需要多节点;同步双写、异步刷盘(同步刷盘可靠性更高,但是效率较异步刷盘要低)
        consumer端:消息消费务必保留日志,即消息的元数据和消息体做好幂等性处理。
    

    7) 理解消息幂等性处理的解决方案

    RocketMQ不保证消息不重复。想要保证消息不重复,需要自己在业务端去重。
    接口幂等性保障,消费端处理业务消息需要消息幂等性时,可以使用Redis、关系数据库等来配合验证消息是否被消费。
    

    8)理解RokcetMQ事务消息的处理流程

    1、生产者发送半消息
    2、MQ服务端返回发送成功给生产者
    3、发送成功执行本地事务
    4、发送二次确认到MQ服务端,确认事务的提交或者回滚
    5、如果未收到确认信息则执行回查
    6、检查本地事务的事务状态
    7、根据检查结果最后确认提交事务或者回滚消息
    

    4, ElasticSearch
    1)ElasticSearch的检索方式,包括url查询 DSL查询
    2)Es的数据管理(增删改)
    新增

    1、使用自己的ID创建
    PUT {index}/_doc/{id}
    {
      "field": "value",
      ...
    }
    2、使用内置ID创建
    POST {index}/_doc
    {
      "field": "value",
      ...
    }
    

    删除

    //通过id删除
    DELETE WONIU56/_DOC/1
    
    //索引库删除
    DELETE WONIU56
    
    //通过条件删除
    POST woniu56/_delete_by_query
    {
    "query": {
        "match": {
          "name": "wagnwu"
        }
      }
    }
    

    更新

    PUT {index}/_doc/{id}
    {
      "field": "value",
      ...
    }
    

    3)常用的数据类型

    数值:long  integer  short  byte  double  float
    文本:text  keyword(不分词)
                keyword可以设置一个长度值,但是该长度值代表的是索引的长度,不是内容长度。  "ignore_above": 2
    日期:date   默认格式:"yyyy-MM-ddTHH:mm:ss"
                可以通过"format0":"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"设置自定义的格式
    

    4)掌握索引库的创建方式(mapping)

    PUT woniu56
    {
      "mappings": {
        //公共的参数设定
        //属性的设置
        "properties": {
          "name": {
            "type": "keyword",
            "ignore_above": 2
          },
          "age": {
            "type": "integer",
            "index": false
          },
          "desc": {
            "type": "text"
          },
          "day": {
            "type": "date",
            "format": "yyyy-MM-dd HH:mm:ss"
          },
          "addr": {
            "type": "geo_point"
          }
        }
      }
    }
    

    5)理解Es搜索的原理:倒排索引与正排索引的区别

            倒排索引:先将文档进行分词处理,标记每个词都出现在哪些文档里面,这样就可以通过标记快速查询某个词所出现的文档位置。
        正排索引:从前往后查找目录,就是正排索引。
    

    6)掌握kibana的基本使用方式

    Kibana是一个开源的分析与可视化平台,设计出来用于和Elasticsearch一起使用的。可以用kibana搜索、查看存放在Elasticsearch中的数据。
    

    7)理解Es与关系型数据库以及Redis数据库的区别跟各自的使用场景

    如果对数据的读写要求极高,并且你的数据规模不大,也不需要长期存储,选redis;
    如果需要构造一个搜索引擎或者你想搞一个看着高大上的数据可视化平台,选ElasticSearch;