实训笔记7.22

实训笔记7.22

  • 7.22
    • 一、MapReduce中的Shuffle机制
      • 1.1 第一块内容:MapTask的输出的分区问题
        • 1.1.1 计算分区的机制
        • 1.1.2 分区数和NumReduceTask的关系
      • 1.2 第二块内容:MapTask的输出的环形缓冲区的问题
      • 1.3 第三块内容:MapTask的输出的溢写排序的问题
      • 1.4 第四块内容(可选操作-MR优化策略):MapTask输出数据时的Combiner局部聚合问题
      • 1.5 第五块内容:ReduceTask拉取数据的分组排序的问题
    • 二、MpReduce的工作流程:详细的工作流程
      • 2.1 第一步、提交MR作业资源
      • 2.2 第二步:运行MapTask任务
      • 2.3 第三步:运行ReduceTask任务
      • 2.4 第四步:输出计算结果
    • 三、MapReduce中Job提交作业机制
    • 四、MapReduce中MapTask作业机制
    • 五、MapReduce中的ReduceTask机制
      • 5.1 第一知识点:ReduceTask任务数的设置
      • 5.2 第二个知识点(非常重要):数据倾斜问题:Map阶段和Reduce阶段都存在
    • 六、MapReduce中的OutputFormat机制
      • 6.1 OutputFormat常见的实现类
        • 6.1.1 TextOutputFormat:是OutputFormat的默认实现类
        • 6.1.2 SequenceFileOutputFormat
      • 6.2 自定义OutputFormat
    • 七、代码示例

7.22

一、MapReduce中的Shuffle机制

Shuffle译为重新洗牌,在大数据中,shuffle指的是将大数据计算所需的相关数据重新“打乱”,需要跨计算节点,跨网络传输数据,如果Shuffle过程中,需要传输的数据量过大,那么分布式计算的效率的偏低。在MapReduce中,Shuffle机制需要涉及到大量的磁盘IO(数据从内存写入到磁盘当中)—磁盘IO也是影响计算性能的核心因素 【MapReduce的优化操作】提升MR程序的计算效率,优化基本上都是对shuffle阶段进行优化

1.1 第一块内容:MapTask的输出的分区问题

MapTask输出数据时,先计算kv数据的分区,计算出分区编号以后,然后将kv以及分区编号借助collector收集器将数据写出到环形缓冲区中

1.1.1 计算分区的机制

  1. 分区数(底层就是NumReduceTask)如果等于1的时候:底层会借助一个Partitioner的匿名内部类的形式去计算分区编号,计算逻辑直接返回的就是0
partitioner = new org.apache.hadoop.mapreduce.Partitioner <K,v>() {@Overridepublic int getPartition(K key, V value, int numPartitions){ return partitions - 1;
}
};
  1. 分区数如果大于1的时候:底层会使用我们在Driver驱动程序设置的分区类,如果分区类没有设置,那么默认使用HashPartitioner类进行分区
if(partitions>1){partitioner=(org.apache.hadoop.mapreduce.Partitioner<K,V>)ReflectionUtils.newInstance(jobContext.getPartitionerClass(),job);
}else{

1.1.2 分区数和NumReduceTask的关系

  1. 一个ReduceTask只能处理一个分区的数据,因此原则上ReduceTask的数量和分区数必须是一致的

  2. 如果分区数和ReduceTask的数量如果不一致出现以下三种情况

    1. 自定义的分区数大于1,但是ReduceTask的数量等于1,此时程序正常运行,返回一个底层的匿名内部类的分区器进行分区,所有的数据都到0号分区了,自定义的分区类没有任何的用户
    2. 自定义的分区数大于1,ReduceTask的数量大于1 但是小于分区数,程序运行会报错
    3. 自定义的分区数据大于1,reduceTask的数量大于1 而且大于自定义的分区数,程序会正常运行,按照我们自己定义的分区机制运行,只不过多余的ReduceTask会空运行。

1.2 第二块内容:MapTask的输出的环形缓冲区的问题

  1. 当我们计算完成kv数据的分区之后,MR程序会借助collector收集器的collect方法将kv数据以及分区编号向环形缓冲区写入,环形缓冲区是一个内存中概念,在底层源码当中就是一个字节数组byte[] kvbuffer。

  2. 环形缓冲区默认只有100M,而且环形缓冲区还有一个阈值,阈值默认是80%,如果缓冲区写入的数据超过了阈值,缓冲区的已经写入的数据会溢写到磁盘文件中spliiN.out文件,同时溢写的过程中,会在环形缓冲区剩余的20%的空间反向继续写入后续的MapTask计算完成的数据。

  3. 环形缓冲区大小和阈值可以自己设置的:

mapreduce.task.io.sort.mb 100M 设置环形缓冲区的大小

mapreduce.map.sort.spill.percent 0.8 设置环形缓冲区的溢写因子

【优化机制】:如果想让MR程序执行的更加快速,在缓冲区这块我们可以减少溢写磁盘的次数,因此一般况下对于不同的计算程度可以设置缓冲区的大小和阈值,减少溢写次数

1.3 第三块内容:MapTask的输出的溢写排序的问题

  1. 环形缓冲区在进行溢写的时候,会先对环形缓冲区的数据按照不同的分区,按照分区的key值的比较器进行排序,排序的目的保证溢写文件分区有序。因此在MR程序,要求MapTask输出的key值必须实现WritableComparable接口,并且重写序列化和反序列化机制以及比较器方法,同时在比较器方法中重写比较规则。MapReduce溢写文件的时候,是一次性全部写入的,全部溢写完成以后清空环形缓冲区的溢写数据。

  2. 溢写磁盘的时候,每一次溢写都会进行一次排序,溢写的排序底层默认使用的是快速排序算法实现的。

  3. MapTask运行过程中,可能产生多个溢写文件,最后多个溢写文件合并成一个大的溢写文件,合并大的溢写文件的时候,还得需要进行一次排序操作,排序采用的归并排序算法。

【问题】:重写比较器的比较方法时,一定要注意,比较器返回的值只能是正整数或者负整数,但千万不能是0,因为一旦是0,那么两个相等的数据只会保留一个。

1.4 第四块内容(可选操作-MR优化策略):MapTask输出数据时的Combiner局部聚合问题

  1. Combiner是MapReduce的可选组件,可以添加也可以不加,如果我们添加了Combiner,Combiner是在map输出之后,reduce输入之前执行的,Combiner在这个过程中,执行几次,执行时机都是不确定的。和MR程序的计算负载,资源是有很大关系的,有可能Combiner设置了,一次也不执行。

  2. Combiner可以理解为Map端的局部聚合,Combiner的存在,可以减少Map端的溢写文件的数据量以及Map向Reduce传输的数据量

  3. 并不是所有的MR程序都可以添加Combiner,Combiner使用的前提是不能影响MR程序的执行逻辑。如果使用MapReduce程序计算平均值等操作,Combiner一定不能存在。

  4. 如果我们要自定义Combiner,Combiner的输入和输出的kv类型必须和Map阶段的输出类型保持一致。Combiner其实就是一个Reducer。所以在有些情况下,如果Combiner和Reducer的逻辑是一样的,同时Reducer的输入和输出满足Combiner的要求,那么可以使用Reducer充当Combiner使用。

1.5 第五块内容:ReduceTask拉取数据的分组排序的问题

  1. ReduceTask是和分区一一对应的,一个ReduceTask用来处理一个分区的数据,ReduceTask处理的分区数据可能是来自多个MapTask,因此ReduceTask在进行计算之前,需要先进行一个copy阶段,copy阶段主要是将每一个MapTask上该分区的数据拉去到ReduceTask所在的节点上。默认拉去到ReduceTask内存中,如果内存放不下Spill溢写操作

  2. 因为ReduceTask拉取得数据量可能很大,拉取 得过程中也会对数据进行merge合并操作

  3. ReduceTask把数据拉取合并完成之后,需要进行分组以及排序,排序merge合并完成之后,需要对整体的拉取的数据再进行一次归并排序,分组将该分区的数据按照key值划分不同的数据组,然后一组相同的key值调用一次Reduce方法进行处理。

  4. 排序默认使用的是key值的比较器进行排序的,分组默认基于key值的判断相等(hashCode、equals)策略进行key值相等判断以外,还会借助比较器进行key值的相等判断,如果hashCode和equals判断两个key值相等,但是比较器比较出来两个对象大小不一致,那么此时MR程序也会认为两个key值不等,划分不同的组中。 MR程序中判断相等比较器是主力。

  5. 默认情况下,reduce聚合key值的时候,需要对key值进行分组,但是key值分组的时候默认使用的是map阶段输出key值的比较器进行相等判断。但是在有些情况下,我们reduce聚合key值并不是按照map阶段的key值的比较器进行分组,因此我们就需要在Reduce阶段在单独定义分组排序,分组排序的目的是为了告诉reduce你应该如何进行分组

  6. reduce端的分组排序如果我们要自定义,只需要继承一个类即可WritableComparator

二、MpReduce的工作流程:详细的工作流程

2.1 第一步、提交MR作业资源

  1. InputFormat生成切片规划文件job.split文件
  2. 将整个MR程序的相关配置项全部封装到一个job.xml配置文件
  3. 借助jobSummitter提交切片规划文件以及配置文件到指定的目录

2.2 第二步:运行MapTask任务

  1. 通过InputFormat的createRecordReader读取对应切片的kv数据
  2. 通过mapTask的map方法进行kv数据的处理
  3. 调用context.write方法将map处理完成的kv数据写出,先计算kv数据的分区编号
  4. 调用collector收集器将kv数据以及分区写出到环形缓冲区,
  5. 环形缓冲区到达一定的阈值之后,先对环形缓冲区数据进行排序,排好序之后将数据一次性溢写到文件中,清空溢写的数据缓冲区,溢写可能会发生多次,也就可能会产生多个溢写文件,当map任务运行完成,多个溢写文件会合并成一个大的溢写文件spill.out,同时合并大文件需要进行排序。
  6. 溢写的过程中如果设置了Combiner,那么溢写的过程中会进行Combiner操作,Combiner到底什么时机执行,不一定,Combiner作用是为了减少了map溢写的数据量以及map向reduce传输的数据量

2.3 第三步:运行ReduceTask任务

  1. copy阶段:先从不同的MapTask上拷贝指定分区的数据到达ReduceTask的节点内存,内存放不下,溢写磁盘文件中
  2. merge阶段:拷贝数据到ReduceTask中,溢写数据的时候会进行合并操作,减少溢写文件的产生
  3. Sort阶段:安装指定的分组规则对数据进行聚合,同时对merge合并完成的数据进行一次排序
  4. 执行Reduce方法,一组相同key调用一次reduce方法

2.2 第三步~第六步 – > 2.3 第一步~第三步:mapreduce中shuffle机制

2.4 第四步:输出计算结果

reduce计算完成,调用context.write方法写出key value数据,MR底层会调用OutputFormat的实现类实现数据到文件的写出

三、MapReduce中Job提交作业机制

核心重点:不同的InputFormat实现类的切片机制

job提交作业的源码解读

四、MapReduce中MapTask作业机制

  1. 不同的InputFormat实现类的读取切片的kv机制
  2. MapTask的任务数的决定机制–切片
  3. MapTask运行过程中内存相关配置
  4. MapTask的运行节点和负责的切片节点之间的关系:移动数据不如移动计算的机制

五、MapReduce中的ReduceTask机制

ReduceTask把数据分组好以后,一组相同的key调用一次Reduce方法,Reduce方法就可以去聚合数据,进行逻辑计算。

5.1 第一知识点:ReduceTask任务数的设置

  1. MR程序当中,MapTask的数量我们是基于切片数量自动确定的,我们人为无法手动设置mapTask的任务数,如果想修改MapTask的个数,我们无法直接修改,只能通过修改切片机制间接的修改MapTask的任务个数。

  2. MR程序当中,ReduceTask的数量机制和MapTask机制不太一样的,ReduceTask的任务个数是可以手动指定的。因此ReduceTask的数量给多少合适?默认要求ReduceTask的数量必须和分区数保持一致,因为一个Reduce任务处理一个分区的数据。

  3. 【注意】在MR程序中,有一个比较特殊的机制,Reduce的数量可以设置为0,那么一旦ReduceTask的数量设置为0,那么MR程序只有Mapper阶段,没有reduce阶段,map阶段的输出就是整个MR程序的最终输出了。 一般写MR程序的时候,要求如果操作不涉及到对数据集整体的聚合操作(计算的结果需要从数据集整体中获得),我们都不建议大家增加Reduce阶段,因为增加了Reduce,MR执行效率会非常的低。

5.2 第二个知识点(非常重要):数据倾斜问题:Map阶段和Reduce阶段都存在

  1. 数据倾斜不是MR程序运行原理,是MR程序在运行过程中可能会出现一种影响MR程序运行效率的情况。所谓的数据倾斜指的是多个ReduceTask处理的分区数据量差距过大,这样的话就会导致一个问题,有些ReduceTask会快速的运行完成,而有些ReduceTask运行时间非常久。
  2. 如果我们发现所有reduceTask,有大部分运行很块结束了,而少部分Task运行时间过长,这一般都是因为数据倾斜问题的导致。解决方案很简单
    1. 自定义分区机制,尽可能让各个分区的数据分布均匀一点
    2. 消除热点key的数据,分区之所以不均匀,还有很大的可能性是因为确实有部分的key值出现的次数太了。消除机制在处理数据时候,在热点key值的后面增加一些随机数。
    3. 抽样分析数据–数学算法和思想

六、MapReduce中的OutputFormat机制

OutputFormat是MR程序中输出格式化类,抽象类中定义了一个方法getRecordWriter,方法是OutputFormat的核心作用,方法作用就是定义了我们的Reduce或者Map阶段输出最终的结果数据时,kv数据如何写入到文件中。写入的规则是一个什么规则。

6.1 OutputFormat常见的实现类

6.1.1 TextOutputFormat:是OutputFormat的默认实现类

  1. 输出数据的规则是将reduce输出的每一个key-value数据以\t分割,然后一组kv数据单独占据一行

  2. 通过这个类输出数据时,会数据放到指定的文件,文件默认的命名规则part-m/r-xxxxx

6.1.2 SequenceFileOutputFormat

  1. 是Hadoop中一种特殊的输出文件格式,输出文件格式SequenceFile文件

  2. SequenceFile文件

    1. SequenceFile文件是Hadoop提供的一种特殊的二进制文件,二进制文件支持对数据进行压缩以后再写出到文件内部,这种文件在某种程度上可以极大的提高分布式计算的效率。SequenceFile文件存储数据的格式都是kv格式,只不过kv数据都是二进制压缩过的数据。
    2. Sequencefile文件支持对数据压缩,也可以不压缩,整体上文件的压缩方式一共有三种
      1. none:对数据不压缩
      2. record:只对kv数据中value数据进行压缩
      3. block:将多个kv数据都进行压缩

6.2 自定义OutputFormat

七、代码示例

package com.sxuek.group;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.net.URI;/*** MR程序辅助排序(分组排序)的案例:*    辅助排序是reduce拉取完数据之后执行,通过辅助排序,reduce可以判断哪些key值为相同的key,如果没有辅助排序,那么MR程序会使用map阶段输出的key的排序规则当作key值判断相等的条件** 现在有一个订单文件,格式如下:*   订单id	    商品id	成交金额*   0000001	Pdt_01	222.8*   0000001	Pdt_05	25.8*   0000002	Pdt_03	522.8*   0000002	Pdt_04	122.4*   0000002	Pdt_05	722.4*   0000003	Pdt_01	222.8*   0000003	Pdt_02	33.8* 这个文件三列,每一列之间都是以\t分割的。现在我们需要基于上述的文件求每一个订单中成交金额最大的商品。结果如下:*   0000001   pdt_01   222.8*   0000002   Pdt_05	722.4*   0000003   pdt_01   222.8** 案例分析:*   如果我们只是想把订单数据按照订单编号从低到高排序,同时如果订单编号一致,那么按照成交金额从高到底排序。*   到时候只需要按照订单id分组,取第一条数据,第一条数据就是我们某一个订单中成交金额最大的商品信息** 如果我们要获取每一个订单的成交金额最大的信息,逻辑只需要在刚刚的代码基础之上,reduce在进行汇总数据的时候,重新指定一下分组规则即可。* 分组条件应该是只要订单id一致即可。如果订单id一致,多个订单数据只有第一条数据才会进入reduce。*/
public class OrderDriver {public static void main(String[] args) throws Exception {Configuration configuration = new Configuration();configuration.set("fs.defaultFS","hdfs://192.168.68.101:9000");Job job = Job.getInstance(configuration);job.setJarByClass(OrderDriver.class);FileInputFormat.setInputPaths(job,new Path("/order.txt"));job.setMapperClass(OrderMapper.class);job.setMapOutputKeyClass(OrderBean.class);job.setMapOutputValueClass(NullWritable.class);job.setGroupingComparatorClass(OrderGroupComparator.class);job.setReducerClass(OrderReducer.class);job.setOutputKeyClass(NullWritable.class);job.setOutputValueClass(OrderReducer.class);job.setNumReduceTasks(1);//默认就是只有一个reduce任务Path path = new Path("/orderOutput");FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.68.101:9000"), configuration, "root");if (fileSystem.exists(path)){fileSystem.delete(path,true);}FileOutputFormat.setOutputPath(job,path);boolean b = job.waitForCompletion(true);System.exit(b?0:1);}
}/*** map阶段的逻辑就是把每一行的订单数据读取进来以后,按照\t分割,将每一行的数据字段以orderBean对象封装,* 封装好以后以orderBean为key  以null值为value输出即可* 那么MR程序在计算过程中会自动根据OrderBean定义的排序规则对数据进行排序*/
class OrderMapper extends Mapper<LongWritable, Text,OrderBean, NullWritable>{@Overrideprotected void map(LongWritable key, Text value, Mapper<LongWritable, Text, OrderBean, NullWritable>.Context context) throws IOException, InterruptedException {String line = value.toString();String[] array = line.split("\t");String orderId = array[0];String pId = array[1];double amount = Double.parseDouble(array[2]);OrderBean orderBean = new OrderBean(orderId,pId,amount);context.write(orderBean,NullWritable.get());}
}/*** Reducer阶段,reduce阶段只需要将读取进来的key value数据输出即可,因为排序规则在map到reduce中间的shuffle阶段已经全自动化完成了* 因此如果只是排序规则,到了reduce阶段只需要将处理好的数据原模原样的输出即可*/
class OrderReducer extends Reducer<OrderBean,NullWritable,NullWritable,OrderBean>{@Overrideprotected void reduce(OrderBean key, Iterable<NullWritable> values, Reducer<OrderBean, NullWritable, NullWritable, OrderBean>.Context context) throws IOException, InterruptedException {context.write(NullWritable.get(),key);}
}/*** 定义辅助排序,重新定义reduce的key值分组逻辑:*   如果orderId一致 认为两条数据是同一个可以 reduce聚合的时候使用第一条数据当作key值进行计算*/
class OrderGroupComparator extends WritableComparator{public OrderGroupComparator(){super(OrderBean.class,true);}@Overridepublic int compare(WritableComparable a, WritableComparable b) {OrderBean o1 = (OrderBean) a;OrderBean o2 = (OrderBean) b;return o1.getOrderId().compareTo(o2.getOrderId());}
}/*** 因为你要对数据进行排序,排序的规则还涉及到多个不同的字段,MR程序中只有map阶段输出的key才具备排序的能力* 因此也就意味着多个排序字段都要当作map输出key来传递,但是key值只能传递一个,多个字段封装为一个JavaBean* 1、定义一个封装原始数据的JavaBean类*/
class OrderBean implements WritableComparable<OrderBean>{private String orderId;private String pId;private Double amount;public OrderBean() {}public OrderBean(String orderId, String pId, Double amount) {this.orderId = orderId;this.pId = pId;this.amount = amount;}public String getOrderId() {return orderId;}public void setOrderId(String orderId) {this.orderId = orderId;}public String getpId() {return pId;}public void setpId(String pId) {this.pId = pId;}public Double getAmount() {return amount;}public void setAmount(Double amount) {this.amount = amount;}@Overridepublic String toString() {return orderId+"\t"+pId+"\t"+amount;}/*** 比较器:想按照订单id升序排序,如果订单id一致 按照成交金额降序排序* @param o the object to be compared.* @return*/@Overridepublic int compareTo(OrderBean o) {if(this.orderId.compareTo(o.orderId) == 0){//判断成交金额if (this.amount > o.amount){return -1;}else if(this.amount < o.amount){return 1;}else{return 0;}}else{return this.orderId.compareTo(o.orderId);}}/*** 序列化写的方法* @param out <code>DataOuput</code> to serialize this object into.* @throws IOException*/@Overridepublic void write(DataOutput out) throws IOException {out.writeUTF(orderId);out.writeUTF(pId);out.writeDouble(amount);}@Overridepublic void readFields(DataInput in) throws IOException {orderId = in.readUTF();pId = in.readUTF();amount = in.readDouble();}
}
package com.sxuek.noreduce;import com.sxuek.group.*;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;import java.io.IOException;
import java.net.URI;/*** 现在有一个文件,文件中有很多行数据,每一行数据都是以空格分割的多个单词组成的,* 现在要求通过MR程序实现将文件中所有以大写字母开头的英语单词过滤掉,最终输出结果文件,结果文件* 中只有以小写字母开头的英语单词。*/
public class DemoDriver {public static void main(String[] args) throws Exception {Configuration configuration = new Configuration();configuration.set("fs.defaultFS","hdfs://192.168.68.101:9000");Job job = Job.getInstance(configuration);job.setJarByClass(DemoDriver.class);FileInputFormat.setInputPaths(job,new Path("/wordcount.txt"));/*** 当前MR程序只有map阶段 没有reduce阶段,* 也就意味着map阶段的输出就是最终的结果数据*/job.setMapperClass(DemoMapper.class);job.setOutputKeyClass(NullWritable.class);job.setOutputValueClass(Text.class);/*** 如果mr程序中没有reduce阶段,一定一定要把reduce的任务数设置为0,* 如果没有设置为0,同时MR程序中没有指定reducer类,那么MR程序会默认自动给你添加Reduce类,并且启动* 一个reduceTask,自动生成的reduce类很简单,reduce类就是map输出的是什么结果  reducer原模原样输出*/job.setNumReduceTasks(0);Path path = new Path("/demoOutput");FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.68.101:9000"), configuration, "root");if (fileSystem.exists(path)){fileSystem.delete(path,true);}FileOutputFormat.setOutputPath(job,path);boolean b = job.waitForCompletion(true);System.exit(b?0:1);}
}
class DemoMapper extends Mapper<LongWritable, Text, NullWritable,Text>{@Overrideprotected void map(LongWritable key, Text value, Mapper<LongWritable, Text, NullWritable, Text>.Context context) throws IOException, InterruptedException {String line = value.toString();System.out.println(line);String[] words = line.split(" ");for (String word : words) {System.out.println(word);char c = word.charAt(0);if (c >=65 && c <=90){continue;//过滤操作 只要map方法执行完成,没有调用context.write方法将数据写出 那么就代表当前数据需要舍弃}else{context.write(NullWritable.get(),new Text(word));}}}
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用Apache Commons Chain实现责任链模式实例

介绍 责任链模式是一种行为型设计模式&#xff0c;用于将多个处理器对象组织成一条链&#xff0c;并沿着链传递某个请求&#xff0c;直到有一个处理器对象能够处理该请求为止。它的核心是将请求和处理器对象解耦&#xff0c;让请求在不知道哪个处理器对象能够处理它的情况下&a…

Mysql数据库

目录 1.数据库 2.数据库分类与常见的数据库 3.SQL 3.1.DDL 数据库操作 表操作 3.2.DML 3.3.DQL 3.4.DCL 管理用户 权限控制 4.Mysql常用的数据类型 1.数据库 数据库:是“按照数据结构来组织、存储和管理数据的仓库”。是一个长期存储在计算机内的、有组织的、可共…

Spring MVC异常处理【单个控制异常处理器、全局异常处理器、自定义异常处理器】

目录 一、单个控制器异常处理 1.1 控制器方法 1.2 编写出错页面 1.3 测试结果 二、全局异常处理 2.1 一个有异常的控制器类 2.2 全局异常处理器类 2.3 测试结果 三、自定义异常处理器 3.1 自定义异常处理器 3.2 测试结果 往期专栏&文章相关导读 1. Maven系列…

只需3步,使用Stable Diffusion无限生产AI数字人视频

效果演示 先看效果&#xff0c;感兴趣的可以继续读下去。 没有找到可以上传视频的地方&#xff0c;大家打开这个网盘链接观看&#xff1a;https://www.aliyundrive.com/s/CRBm5NL3xAE 基本方法 搞一张照片&#xff0c;搞一段语音&#xff0c;合成照片和语音&#xff0c;同…

SpringBoot+jasypt-spring-boot-starter实现配置文件明文加密

1.使用环境 springboot:2.1.4.RELEASE JDK:8 jasypt-spring-boot-starter:3.0.2 2.引入依赖 !-- 配置文件加密 --> <dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><ver…

uni-app:请求后端数据uni.request

完整代码&#xff1a; onLoad() {uni.request({url: getApp().globalData.position Produce/select_employee,data: {username: getApp().globalData.username,},method: POST,dataType: json,success: res > {this.employee_name res.data.info.employee_name;// consol…

sketch如何在线打开?有没有什么软件可以辅助

Sketch 在线打开的方法有哪些&#xff1f;这个问题和我之前回答过的「Sketch 可以在线编辑吗&#xff1f;」是一样的答案&#xff0c;没有。很遗憾&#xff0c;Sketch 没有在线打开的方法&#xff0c;Sketch 也做不到可以在线编辑。那么&#xff0c;那些广告里出现的设计软件工…

数学建模学习(4):TOPSIS 综合评价模型及编程实战

一、数据总览 需求&#xff1a;我们需要对各个银行进行评价&#xff0c;A-G为银行的各个指标&#xff0c;下面是银行的数据&#xff1a; 二、代码逐行实现 清空代码和变量的指令 clear;clc; 层次分析法 每一行代表一个对象的指标评分 p [8,7,6,8;7,8,8,7];%每一行代表一个…

Docker 基本管理

目录 一、Docker 概述 二、为什么容器越来越受欢迎&#xff1f; 三、Docker 与 虚拟机 的区别 四、 Linux Namespace的6大类型 五、Docker 核心概念 1.镜像 2.容器 3.仓库 六、安装 Docker 1.安装依赖包 2.设置阿里云镜像源&#xff0c;安装Docker 3.查看 docker 版…

PostgreSQL 的事务管理和并发控制机制解析

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

视频参数简介

max-mbps:表示每秒钟能处理的最大宏块数量。 max-fs: 表示接收端能够解码的一帧图像的最大尺寸&#xff0c;这个尺寸用这帧图像包含的宏块数来量化&#xff0c;即max-fs的数值。常见的分辨率与max-fs关系如下&#xff1a; 640x360P : 920 1280x720P: 3600 1920x1080P: 8160 max…

BEVPoolv2 A Cutting-edge Implementation of BEVDet Toward Deployment 论文学习

Github Repo: https://github.com/HuangJunJie2017/BEVDet/tree/dev2.0 Arxiv Paper: https://arxiv.org/abs/2211.17111 1. 解决了什么问题&#xff1f; 多相机 3D 目标检测是自动驾驶领域的基本任务&#xff0c;受到学术界和工业界的大量关注。Lift-Splat-Shoot view trans…

React知识点梳理

React是一个用于构建用户界面的JavaScript库。它采用组件化的开发模式&#xff0c;将用户界面拆分为独立的、可重用的组件&#xff0c;通过组件的组合和交互来构建复杂的用户界面。 下面是React的一些核心概念和知识点的梳理&#xff0c;并附带详细示例&#xff1a; 组件(Comp…

MFC第十九天 记事本项目功能完善和开发、CTabCtrl类与分页模式开发

文章目录 记事本项目功能完善和开发查找界面的记忆功能 、使用F3快捷键自动向下查找功能 的开发单次替换的算法研究 CFileDialog 构造函数详解 应用另存为时选择编码 &#xff08;三种方案&#xff09;vista 样式文件对话框 bVistaStyle 为TRUE时 1pch.hCApp NotePad.cpp 对编码…

视频对比工具(基于python+ffmpeg+airtest实现视频抽帧比较工具)

VideoDiff&#xff1a;基于ffmpeg&#xff0c;实现视频抽帧比较工具 使用场景&#xff1a;在视频渲染模块发生迭代&#xff0c;快速回归测试其产出的视频是否存在问题&#xff0c;从而节省人工回归成本 源码地址&#xff1a;https://github.com/jiangliuer32/VideoDiff 原理图…

软件架构演进过程与微服务设计中的领域驱动设计(DDD)

软件架构的演进是一个不断改进和解决问题的过程。从传统架构到面向服务架构(SOA)&#xff0c;再到微服务架构&#xff0c;每个阶段都带来了新的技术和解决方案。而在微服务架构中&#xff0c;领域驱动设计(DDD)起着至关重要的作用&#xff0c;它能够提高系统的可扩展性、可维护…

快速响应和恢复:使用自动化测试进行系统性能测试

快速响应和恢复&#xff1a;使用自动化测试进行系统性能测试 在当今数字化时代&#xff0c;用户对于应用程序性能的期望越来越高。快速响应和恢复是确保用户满意度和业务成功的关键因素之一。为了保证应用程序在不同负载和条件下的可靠性和稳定性&#xff0c;进行系统性能测试…

centos7中MySQL备份还原策略

目录 一、直接拷贝数据库文件 1.1在shangke主机上停止服务并且打包压缩数据库文件 1.2 在shangke主机上把数据库文件传输到localhost主机上(ip为192.168.33.157) 1.3在localhost主机上停止服务&#xff0c;解压数据库文件 1.4 在localhost主机上开启服务 1.5 测试 二、m…

在vue项目中使用postcss-px2rem插件把px转变为rem,并配合给html根元素设置fontsize,来实现页面的自适应效果

在vue项目中使用postcss-px2rem插件把px转变为rem&#xff0c;并配合给html根元素设置fontsize&#xff0c;来实现页面的自适应效果 安装postcss-px2rem插件&#xff0c;目的&#xff1a;把px转变为remvue.config.js中配置remUnit通过js改变html的fontsize值postcss-px2rem插件…

JVM-Java虚拟机

JVM——Java虚拟机&#xff0c;是Java实现平台无关性的基石。 基本概念&#xff1a;JVM 是可运行 Java 代码的假想计算机 &#xff0c;包括一套字节码指令集、一组寄存器、一个栈、 一个垃圾回收&#xff0c;堆 和 一个存储方法域。JVM 是运行在操作系统之上的&#xff0c;它与…