当前位置: 首页 > news >正文

大数据框架之Hadoop:MapReduce(三)MapReduce框架原理——shuffle机制

3.3.1Shuffle机制

Map方法之后,Reduce方法之前的数据处理过程称之为Shuffle。

Untitled

3.3.2Partition分区

1、问题引出

要求将统计结果按照条件输出到不同文件中(分区)。比如:将统计结果按照手机归属地不同省份输出到不同文件中(分区)

2、默认Partitioner分区

public int getPartition(K2 key, V2 value,int numReduceTasks) {return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;

默认分区是根据key的hashCode对ReduceTasks个数取模得到的。用户没法控制哪个key存储到哪个分区。

3、自定义Partitioner步骤

(1)自定义类继承Partitioner,重写getPartition()方法

public class ProvincePartitioner extends Partitioner<Text, FlowBean> {@Overridepublic int getPartition(Text key, FlowBean value, int numPartitions) {//控制分区代码逻辑...return partition;}
}

(2)在Job驱动中,设置自定义Partitioner

job.setPartitionerClass(ProvincePartitioner.class);

(3)自定义Parttition后,要根据自定义Partitioner的逻辑设置相应数量的ReduceTask

// 9 同时指定相应数量的reduce task
job.setNumReduceTasks(5);

4、分区总结

(1)如果ReduceTask的数量>getPartition的结果数,则会多昌盛几个空的输出文件part-r000xx;

(2)如果1<ReduceTask的数量<getPartition的结果数,则有一部分分区数据无处安放,会Exception;

(3)如果ReduceTask的数量=1,则不管MapTask端输出多少个分区文件,最终结果都交给这一个ReduceTask,最终也就只会产生一个结果文件part-r-00000;

(4)分区号必须从零开始,逐一累加。

5、案例分析

例如:假设自定义分区数为5,则

(1)job.setNumReduceTasks(1);会正常运行,只产生一个输出文件

(2)job.setNumReduceTasks(2); 会报错

(3)job.setNumReduceTasks(6); 大于5,程序会正常运行,会产生空文件

3.3.3Partition分区案例实操

1、需求

将统计结果按照手机归属地不同省份输出到不同文件中(分区)

(1)输入数据

1	13736230513	192.196.100.1	www.atguigu.com	2481	24681	200
2	13846544121	192.196.100.2			264	0	200
3 	13956435636	192.196.100.3			132	1512	200
4 	13966251146	192.168.100.1			240	0	404
5 	18271575951	192.168.100.2	www.atguigu.com	1527	2106	200
6 	84188413	192.168.100.3	www.atguigu.com	4116	1432	200
7 	13590439668	192.168.100.4			1116	954	200
8 	15910133277	192.168.100.5	www.hao123.com	3156	2936	200
9 	13729199489	192.168.100.6			240	0	200
10 	13630577991	192.168.100.7	www.shouhu.com	6960	690	200
11 	15043685818	192.168.100.8	www.baidu.com	3659	3538	200
12 	15959002129	192.168.100.9	www.atguigu.com	1938	180	500
13 	13560439638	192.168.100.10			918	4938	200
14 	13470253144	192.168.100.11			180	180	200
15 	13682846555	192.168.100.12	www.qq.com	1938	2910	200
16 	13992314666	192.168.100.13	www.gaga.com	3008	3720	200
17 	13509468723	192.168.100.14	www.qinghua.com	7335	110349	404
18 	18390173782	192.168.100.15	www.sogou.com	9531	2412	200
19 	13975057813	192.168.100.16	www.baidu.com	11058	48243	200
20 	13768778790	192.168.100.17			120	120	200
21 	13568436656	192.168.100.18	www.alibaba.com	2481	24681	200
22 	13568436656	192.168.100.19			1116	954	200

(2)期望输出数据

手机号136、137、138、139开头都分别放到一个独立的4个文件中,其他开头的放到一个文件中。

2、需求分析

Untitled

3、在案例2.4的基础上,增加一个分区类

package com.cuiyf41.flowsum;import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;public class ProvincePartitioner extends Partitioner<Text, FlowBean> {@Overridepublic int getPartition(Text key, FlowBean value, int numPartitions) {// 1 获取电话号码的前三位String preNum = key.toString().substring(0, 3);int partition = 4;// 2 判断是哪个省if ("136".equals(preNum)){partition = 0;}else if ("137".equals(preNum)){partition = 1;}else if ("138".equals(preNum)){partition = 2;}else if ("139".equals(preNum)){partition = 3;}return partition;}
}

4、在驱动函数中增加自定义数据分区设置和ReduceTask设置

// 8 指定自定义数据分区
job.setPartitionerClass(ProvincePartitioner.class);// 9 同时指定相应数量的reduce task
job.setNumReduceTasks(5);
package com.cuiyf41.flowsum;import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.CombineTextInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;public class FlowsumDriver {public static void main(String[] args) throws IllegalArgumentException, IOException, ClassNotFoundException, InterruptedException {// 输入输出路径需要根据自己电脑上实际的输入输出路径设置args = new String[] { "e:/input/phone_data.txt", "e:/output" };// 1 获取配置信息,或者job对象实例Configuration conf = new Configuration();Job job = Job.getInstance(conf);// 6 指定本程序的jar包所在的本地路径job.setJarByClass(FlowsumDriver.class);// 2 指定本业务job要使用的mapper/Reducer业务类job.setMapperClass(FlowCountMapper.class);job.setReducerClass(FlowCountReducer.class);// 3 指定mapper输出数据的kv类型job.setMapOutputKeyClass(Text.class);job.setMapOutputValueClass(FlowBean.class);// 4 指定最终输出的数据的kv类型job.setOutputKeyClass(Text.class);job.setOutputValueClass(FlowBean.class);// 5 指定job的输入原始文件所在目录Path input = new Path(args[0]);Path output = new Path(args[1]);// 如果输出路径存在,则进行删除FileSystem fs = FileSystem.get(conf);if (fs.exists(output)) {fs.delete(output,true);}FileInputFormat.setInputPaths(job, input);FileOutputFormat.setOutputPath(job, output);// 8 指定自定义数据分区job.setPartitionerClass(ProvincePartitioner.class);// 9 同时指定相应数量的reduce taskjob.setNumReduceTasks(5);// 7 将job中配置的相关参数,以及job所用的java类所在的jar包, 提交给yarn去运行boolean result = job.waitForCompletion(true);System.exit(result ? 0 : 1);}
}

3.3.4WritableComparable排序

1、概述

排序是MapReduce框架中最重要的操作之一。

MapTask和ReduceTask均会对数据按照key进行排序。该操作属于Hadoop的默认行为。任何应用程序中的数据均会被排序,而不管逻辑上是否需要。

默认排序是按照字典顺序排序,且实现该排序的方法是快速排序

对于MapTask,它会将处理的结果暂时放到环形缓冲区中,当环形缓冲区使用率达到一定阈值时,再对缓冲区中的数据进行一次快速排序,并将这些有序数据溢写到磁盘上,而当数据处理完毕后,它会对磁盘上所有文件进行归并排序。

对于ReduceTask,它从每个MapTask上远程拷贝相应的数据文件,如果文件大小超过一定的阈值,则溢写到磁盘上,否则存储在内存中。如果磁盘上文件数目达到一定阈值,则进行一次归并排序以生成一个更大的文件;如果内存中文件大小或者数量超过一定阈值,则进行一次合并后将数据溢写到磁盘上。当所有数据拷贝完毕后,ReduceTask统一对内存和磁盘上的所有数据进行一次归并排序

2、排序的分类

(1)部分排序

MapReduce根据输入记录的键对数据集排序。保证输出的每个文件内部有序

(2)全排序

最终输出结果只有一个文件,且文件内部有序。实现方式是只设置一个ReduceTask。但该方法在处理大型文件时效率极低,因为一台机器处理所有文件,完全丧失了MapReduce所提供的并行架构。

(3)辅助排序(GroupingComparator分组)

在Reduce端对key进行分组。应用于:在接收的key为bean对象时,想让一个或几个字段相同(全部比较不相同)的key进入到同一个reduce方法时,可以采用分组排序。

(4)二次排序

在自定义排序过程中,如果compareTo中的判断条件为两个即为二次排序。

3、自定义排序WritableComparable

(1)原理分析

bean对象做为key传输,需要实现WritableComparable接口重写compareTo方法,就可以实现排序。

@Override
public int compareTo(FlowBean o) {int result;// 按照总流量大小,倒序排列if (sumFlow > bean.getSumFlow()) {result = -1;}else if (sumFlow < bean.getSumFlow()) {result = 1;}else {result = 0;}return result;
}

3.3.5WritableComparable排序案例实操(全排序)

1、需求

根据案例2.3产生的结果再次对总流量进行排序。

(1)输入数据

原始数据 第一次处理后的数据

(2)期望输出数据

13509468723	7335	110349	117684
13736230513	2481	24681	27162
13956435636	132		1512	1644
13846544121	264		0		264
。。。 。。。

2、需求分析

Untitled

3、代码实现

(1)FlowBean对象在在需求1基础上增加了比较功能

package com.cuiyf41.sort;import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.WritableComparable;import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;public class FlowBean implements WritableComparable<FlowBean> {private long upFlow;private long downFlow;private long sumFlow;// 反序列化时,需要反射调用空参构造函数,所以必须有public FlowBean() {super();}public FlowBean(long upFlow, long downFlow) {this.upFlow = upFlow;this.downFlow = downFlow;this.sumFlow = upFlow + downFlow;}/*** 序列化方法* @param out* @throws IOException*/@Overridepublic void write(DataOutput out) throws IOException {out.writeLong(upFlow);out.writeLong(downFlow);out.writeLong(sumFlow);}/*** 反序列化方法 注意反序列化的顺序和序列化的顺序完全一致* @param in* @throws IOException*/@Overridepublic void readFields(DataInput in) throws IOException {upFlow = in.readLong();downFlow = in.readLong();sumFlow = in.readLong();}@Overridepublic String toString() {return upFlow + "\t" + downFlow + "\t" + sumFlow;}public long getUpFlow() {return upFlow;}public void setUpFlow(long upFlow) {this.upFlow = upFlow;}public long getDownFlow() {return downFlow;}public void setDownFlow(long downFlow) {this.downFlow = downFlow;}public long getSumFlow() {return sumFlow;}public void setSumFlow(long sumFlow) {this.sumFlow = sumFlow;}@Overridepublic int compareTo(FlowBean o) {int result;// 按照总流量大小,倒序排列if (this.sumFlow > o.getSumFlow()) {result = -1;}else if (this.sumFlow < o.getSumFlow()) {result = 1;}else {result = 0;}return result;}public void set(long upFlow, long downFlow) {this.upFlow = upFlow;this.downFlow = downFlow;this.sumFlow = upFlow + downFlow;}
}

(2)编写Mapper类

package com.cuiyf41.sort;import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;import java.io.IOException;public class FlowCountSortMapper extends Mapper<LongWritable, Text, FlowBean, Text> {FlowBean k = new FlowBean();Text v = new Text();@Overrideprotected void map(LongWritable key, Text value, Mapper<LongWritable, Text, FlowBean, Text>.Context context) throws IOException, InterruptedException {// 1 获取一行String line = value.toString();// 2 截取String[] fields = line.split("\t");// 3 封装对象String phoneNum = fields[0];long upFlow = Long.parseLong(fields[1]);long downFlow = Long.parseLong(fields[2]);k.set(upFlow, downFlow);v.set(phoneNum);// 4 输出context.write(k, v);}
}

(3)编写Reducer类

package com.cuiyf41.sort;import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;import java.io.IOException;public class FlowCountSortReducer extends Reducer<FlowBean, Text, Text, FlowBean> {@Overrideprotected void reduce(FlowBean key, Iterable<Text> values, Reducer<FlowBean, Text, Text, FlowBean>.Context context) throws IOException, InterruptedException {// 循环输出,避免总流量相同情况for(Text value: values){context.write(value, key);}}
}

(4)编写Driver类

package com.cuiyf41.flowsum;import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;import java.io.IOException;public class FlowCountMapper extends Mapper<LongWritable, Text, Text, FlowBean> {FlowBean v = new FlowBean();Text k = new Text();@Overrideprotected void map(LongWritable key, Text value, Context context)	throws IOException, InterruptedException {// 1 获取一行String line = value.toString();// 2 切割字段String[] fields = line.split("\t");// 3 封装对象// 取出手机号码String phoneNum = fields[1];// 取出上行流量和下行流量long upFlow = Long.parseLong(fields[fields.length - 3]);long downFlow = Long.parseLong(fields[fields.length - 2]);k.set(phoneNum);
//        FlowBean v = new FlowBean(upFlow, downFlow);v.set(upFlow, downFlow);// 4 写出context.write(k, v);}
}

3.3.6WritableComparable排序案例实操(区内排序)

1.需求

要求每个省份手机号输出的文件中按照总流量内部排序。

2.需求分析

基于前一个需求,增加自定义分区类,分区按照省份手机号设置。

Untitled

3.案例实操

(1)增加自定义分区类

package com.cuiyf41.sort;import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;public class ProvincePartitioner extends Partitioner<FlowBean, Text> {@Overridepublic int getPartition(FlowBean key, Text value, int numPartitions) {// 1 获取手机号码前三位String preNum = value.toString().substring(0, 3);int partition = 4;// 2 根据手机号归属地设置分区if ("136".equals(preNum)) {partition = 0;}else if ("137".equals(preNum)) {partition = 1;}else if ("138".equals(preNum)) {partition = 2;}else if ("139".equals(preNum)) {partition = 3;}return partition;}
}

(2)在驱动类中添加分区类

// 加载自定义分区类
job.setPartitionerClass(ProvincePartitioner.class);// 设置Reducetask个数
job.setNumReduceTasks(5);

3.3.7Combiner合并

1)概述

(1)Combiner是MR程序中Mapper和Reducer之外的一个组件。

(2)Combiner组件的父类就是Reducer。

(3)Combiner和Reducer的区别在于运行的维值

Combiner是在每个MapTask所在的节点运行

Reducer是接收全局所有Mapper的输出结果

(4)Combiner的意义就是对每一个MapTask的输出进行局部汇总,以减少网络传输量。

(5)Combiner能够应用的前提是不能影响最终的业务逻辑,而且Combiner的输出kv应该跟Reducer的输入kv类型保持一致。

Mapper Reducer

3 5 7 →(3+5+7)/3 = 5 (3+5+7+2+6)/5 = 23/5 等于(5+4)/2 = 9/2

2 6 →(2+6)/2 = 4

2)自定义Combiner实现步骤

(a)自定义一个Combiner继承Reducer,重写Reduce方法

public class WordcountCombiner extends Reducer<Text, IntWritable, Text,IntWritable>{@Overrideprotected void reduce(Text key, Iterable<IntWritable> values,Context context) throws IOException, InterruptedException {// 1 汇总操作int count = 0;for(IntWritable v :values){count += v.get();}// 2 写出context.write(key, new IntWritable(count));}
}

(b)在Job驱动类中设置:

job.setCombinerClass(WordcountCombiner.class);

3.3.8Combiner合并案例实操

1、需求

统计过程中对每一个MapTask的输出进行局部汇总,以减小网络传输量即采用Combiner功能。

(1)数据输入

(2)期望输出数据

期望:Combine输入数据多,输出时经过合并,输出数据降低。

2、需求分析

Untitled

3.案例实操-方案一

1)增加一个WordcountCombiner类继承Reducer

package com.cuiyf41.wordcount;import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;import java.io.IOException;public class WordcountCombiner extends Reducer<Text, IntWritable, Text, IntWritable> {IntWritable v = new IntWritable();@Overrideprotected void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {// 1 汇总int sum = 0;for(IntWritable value :values){sum += value.get();}v.set(sum);// 2 写出context.write(key, v);}
}

2)在WordcountDriver驱动类中指定Combiner

// 指定需要使用combiner,以及用哪个类作为combiner的逻辑
job.setCombinerClass(WordcountCombiner.class);

4.案例实操-方案二

1)将WordcountReducer作为Combiner在WordcountDriver驱动类中指定

// 指定需要使用Combiner,以及用哪个类作为Combiner的逻辑
job.setCombinerClass(WordcountReducer.class);

3.3.9GroupingComparator分组(辅助排序)

1)概述

对Reduce阶段的数据根据某一个或几个字段进行分组。

分组排序步骤:

(1)自定义类继承WritableComparator

(2)重写compare()方法

@Override
public int compare(WritableComparable a, WritableComparable b) {// 比较的业务逻辑return result;
}

(3)创建一个构造将比较对象的类传给父类

protected OrderGroupingComparator() {super(OrderBean.class, true);
}

3.3.10GroupingComparator分组案例实操

1、需求

有如下订单数据

Untitled

现在需要求出每一个订单中最贵的商品。

(1)输入数据

0000001	Pdt_01	222.8
0000002	Pdt_05	722.4
0000001	Pdt_02	33.8
0000003	Pdt_06	232.8
0000003	Pdt_02	33.8
0000002	Pdt_03	522.8
0000002	Pdt_04	122.4

(2)期望输出数据

1	222.8
2	722.4
3	232.8

2、需求分析

(1)利用“订单id和成交金额”作为key,可以将Map阶段读取到的所有订单数据按照id升序排序,如果id相同再按照金额降序排序,发送到Reduce。

(2)在Reduce端利用groupingComparator将订单id相同的kv聚合成组,然后取第一个即是该订单中最贵商品,如图4-18所示。

Untitled

3、代码实现

(1)定义订单信息OrderBean类

package com.cuiyf41.order;import org.apache.hadoop.io.WritableComparable;import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;public class OrderBean implements WritableComparable<OrderBean> {private int order_id; // 订单id号private double price; // 价格public OrderBean() {super();}public OrderBean(int order_id, double price) {super();this.order_id = order_id;this.price = price;}// 二次排序@Overridepublic int compareTo(OrderBean o) {int result;if (order_id > o.getOrder_id()) {result = 1;} else if (order_id < o.getOrder_id()) {result = -1;} else {// 价格倒序排序result = price > o.getPrice() ? -1 : 1;}return result;}@Overridepublic void write(DataOutput out) throws IOException {out.writeInt(order_id);out.writeDouble(price);}@Overridepublic void readFields(DataInput in) throws IOException {order_id = in.readInt();price = in.readDouble();}@Overridepublic String toString() {return order_id + "\t" + price;}public int getOrder_id() {return order_id;}public void setOrder_id(int order_id) {this.order_id = order_id;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}
}

(2)编写OrderSortMapper类

package com.cuiyf41.order;import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;import java.io.IOException;public class OrderMapper extends Mapper<LongWritable, Text, OrderBean, NullWritable> {OrderBean k = new OrderBean();@Overrideprotected void map(LongWritable key, Text value, Mapper<LongWritable, Text, OrderBean, NullWritable>.Context context) throws IOException, InterruptedException {// 1 获取一行String line = value.toString();// 2 截取String[] fields = line.split("\t");// 3 封装对象k.setOrder_id(Integer.parseInt(fields[0]));k.setPrice(Double.parseDouble(fields[2]));// 4 写出context.write(k, NullWritable.get());}
}

(3)编写OrderSortGroupingComparator类

package com.cuiyf41.order;import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator;public class OrderGroupingComparator extends WritableComparator {protected OrderGroupingComparator() {super(OrderBean.class, true);}@Overridepublic int compare(WritableComparable a, WritableComparable b) {OrderBean aBean = (OrderBean) a;OrderBean bBean = (OrderBean) b;int result;if (aBean.getOrder_id() > bBean.getOrder_id()) {result = 1;} else if (aBean.getOrder_id() < bBean.getOrder_id()) {result = -1;} else {result = 0;}return result;}
}

(4)编写OrderSortReducer类

package com.cuiyf41.order;import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.mapreduce.Reducer;import java.io.IOException;public class OrderReducer extends Reducer<OrderBean, NullWritable, OrderBean, NullWritable> {@Overrideprotected void reduce(OrderBean key, Iterable<NullWritable> values, Reducer<OrderBean, NullWritable, OrderBean, NullWritable>.Context context) throws IOException, InterruptedException {context.write(key, NullWritable.get());}
}

(5)编写OrderSortDriver类

package com.cuiyf41.order;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;import java.io.IOException;public class OrderDriver {public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {// 输入输出路径需要根据自己电脑上实际的输入输出路径设置args  = new String[]{"e:/input/inputorder" , "e:/output1"};// 1 获取配置信息Configuration conf = new Configuration();Job job = Job.getInstance(conf);// 2 设置jar包加载路径job.setJarByClass(OrderDriver.class);// 3 加载map/reduce类job.setMapperClass(OrderMapper.class);job.setReducerClass(OrderReducer.class);// 4 设置map输出数据key和value类型job.setMapOutputKeyClass(OrderBean.class);job.setMapOutputValueClass(NullWritable.class);// 5 设置最终输出数据的key和value类型job.setOutputKeyClass(OrderBean.class);job.setOutputValueClass(NullWritable.class);// 6 设置输入数据和输出数据路径Path input = new Path(args[0]);Path output = new Path(args[1]);// 如果输出路径存在,则进行删除FileSystem fs = FileSystem.get(conf);if (fs.exists(output)) {fs.delete(output,true);}FileInputFormat.setInputPaths(job, input);FileOutputFormat.setOutputPath(job, output);// 8 设置reduce端的分组job.setGroupingComparatorClass(OrderGroupingComparator.class);// 7 提交boolean result = job.waitForCompletion(true);System.exit(result ? 0 : 1);}
}

相关文章:

大数据框架之Hadoop:MapReduce(三)MapReduce框架原理——shuffle机制

3.3.1Shuffle机制 Map方法之后&#xff0c;Reduce方法之前的数据处理过程称之为Shuffle。 3.3.2Partition分区 1、问题引出 要求将统计结果按照条件输出到不同文件中&#xff08;分区&#xff09;。比如&#xff1a;将统计结果按照手机归属地不同省份输出到不同文件中&#…...

4|无线传感器网络与应用|无线传感器网络原理及方法-许毅版|第3章:无线传感器网络通信-3.1协议结构 3.2物理层|青岛科技大学|课堂笔记

第3章&#xff1a;无线传感器网络通信3.1协议结构3.1.1 OSI参考模型1.网络通信协议MAC层和物理层采用IEEE 802.15.4协议*(1)物理层wsn物理层负责信号的调制和数据的收发&#xff0c;传输介质&#xff1a;无线电、红外线、光波等。(2)数据链路层wsn数据链路层负责数据成帧、帧检…...

关机时,如何控制systemd服务的关闭顺序

关机时&#xff0c;如何控制systemd服务的关闭顺序? 在工作中&#xff0c;我们通常遇到的问题是&#xff0c;如何控制systemd服务的启动顺序&#xff0c;同志们第一反应就会是使用Before或者After去进行控制。 问题来了&#xff0c;如果服务启动时没有顺序要求&#xff0c;但…...

关于MySQL镜像构建过程中添加自动初始化数据库

需求描述一般而言&#xff0c;我们在拉取了 mysql 镜像并运行之后&#xff0c;其中的并不会存在我们自定义的数据库&#xff0c;都是在镜像运行后&#xff0c;自己主动导入数据库&#xff0c;那么有没有方式可以一运行 mysql 镜像&#xff0c;对应生成的 mysql 容器中就有我们自…...

CS144-Lab2

实验架构 除了写入传入流之外&#xff0c;TCPReceiver 还负责通知 sender 两件事&#xff1a; “First unassembled” 字节的索引&#xff0c;称为“acknowledgment”或 “ackno”。这是接收方需要来自发送方的第一个字节。“first unassembled ” 索引和“first unacceptable…...

Linux内核驱动之efi-rtc

Linux内核驱动之efi-rtc1. UEFI与BIOS概述1.1. BIOS 概述1.1.1. BIOS缺点&#xff1a;1.1.2. BIOS的启动流程1.2 UEFI 概述1.2.1 Boot Sevices&#xff1a;1.2.2. Runtime Service&#xff1a;1.2.3. UEFI优点&#xff1a;1.2.4. UEFI启动过程&#xff1a;1.3 Legacy和UEFI1.4 …...

Java 字符串

文章目录一、API二、String1. String 构造方法2. String 对象的特点3. 字符串的比较4. 用户登录案例5. 遍历字符串6. 统计字符次数7. 拼接字符串8. 字符串反转三、StringBuilder1. 构造方法2. 添加及反转方法3. 与 String 相互转换4. 拼接字符串升级版5. 字符串反转升级版一、A…...

麦克风阵列波束基本概念理解

波束形成 本质上是设计合适的滤波器&#xff0c;对于一类固定滤波器系数的阵列来说&#xff0c;无论输入信号或者噪声信号的统计特征如何&#xff0c;其滤波器系数固定不变&#xff0c;此类波束形成叫Fixed Beamforming&#xff0c;固定波束形成好比传统数字信号处理里面的经典…...

JAVA保姆式JDBC数据库免费教程之02-连接池技术

连接池 连接池概念 ​ 概念&#xff1a;其实就是一个容器(集合)&#xff0c;存放数据库连接的容器。 当系统初始化好后&#xff0c;容器被创建&#xff0c;容器中会申请一些连接对象&#xff0c;当用户来访问数据库时&#xff0c;从容器中获取连接对象&#xff0c;用户访问完…...

视频片段怎么做成gif图?快试试这2种方法

动态gif图片作为当下非常常用的表情包&#xff0c;其丰富的内容生动的画面深受大众喜爱。那么&#xff0c;当我们想要将电影或是电视剧中的某一片段做成gif动态图片的时候&#xff0c;要如何操作呢&#xff1f;接下来&#xff0c;给大家分享两招视频转化gif的小窍门–使用【GIF…...

2.20计算机如何工作

一.计算机组成1.冯诺依曼体系CPU 中央处理器: 进行算术运算和逻辑判断.存储器: 分为外存和内存, 用于存储数据(使用二进制方式存储)输入设备: 用户给计算机发号施令的设备.输出设备: 计算机个用户汇报结果的设备内存和外存的区别(面试)访问速度:内存快,外存慢存储空间:内存小,外…...

[golang gin框架] 5.Cookie以及Session

1.Cookie(1).介绍HTTP 是无状态协议,简单地说&#xff0c;当浏览了一个页面&#xff0c;然后转到同一个网站的另一个页面&#xff0c;服务器无法认识到这是同一个浏览器在访问同一个网站,每一次的访问&#xff0c;都是没有任何关系的,如果要实现多个页面之间共享数据的话就可以…...

【牛客刷题专栏】0x0B:JZ3 数组中重复的数字(C语言编程题)

前言 个人推荐在牛客网刷题(点击可以跳转)&#xff0c;它登陆后会保存刷题记录进度&#xff0c;重新登录时写过的题目代码不会丢失。个人刷题练习系列专栏&#xff1a;个人CSDN牛客刷题专栏。 题目来自&#xff1a;牛客/题库 / 在线编程 / 剑指offer&#xff1a; 目录前言问题…...

js中的隐式类型转换有哪些

目录一、隐式类型转换条件二、 的隐式类型转换三、 的隐式类型转换四、object 的隐式类型转换探讨 object 的隐式转换执行顺序探讨 Symbol.toPrimitive 属性如何将对象转换为原始值在前端js这门动态弱类型语言中&#xff0c;不仅存在着显示类型转换&#xff0c;还存在许多隐式类…...

WuThreat身份安全云-TVD每日漏洞情报-2023-02-17

漏洞名称:IBM Aspera Faspex 预身份验证 RCE 漏洞 漏洞级别:高危 漏洞编号:CVE-2022-47986 相关涉及:IBM Aspera Faspex 漏洞状态:POC 参考链接:https://tvd.wuthreat.com/#/listDetail?TVD_IDTVD-2023-02805 漏洞名称:Kardex Mlog MCC PATH 遍历 漏洞级别:严重 漏洞编号:CVE…...

掌握MySQL分库分表(三)水平分库分表常见策略range、hash

文章目录range策略Range策略延伸基于Range范围分库分表业务场景hash取模案例规则水平分库分表&#xff0c;根据什么规则进行划分&#xff1f; range策略 自增id&#xff0c;根据ID范围进行分表&#xff08;左闭右开&#xff09; 规则案例&#xff1a; 1~1,000,000 是 table…...

CTFer成长之路之CTF中的SQL注入

CTF中的SQL注入CTF SQL注入 SQL注入-1 题目描述: 暂无 docker-compose.yml version: 3.2services:web:image: registry.cn-hangzhou.aliyuncs.com/n1book/web-sql-1:latestports:- 80:80启动方式 docker-compose up -d 题目Flag n1book{union_select_is_so_cool} Wri…...

python snap7读写PLC

主要在DB块里操作 读DB块 import snap7 import structdef plc_connection():PLC_IP 192.168.10.10PLC snap7.client.Client()PLC.connect(PLC_IP, rack0, slot1)return PLCPLC plc_connection()PLC.read_area()方法从PLC中读取指定区域的数据。 1200表示DB块的编号&#x…...

使用物联网进行智能能源管理的10大优势

如今&#xff0c;物联网推动了许多行业的自动化流程和运营效率&#xff0c;而物联网在能源领域的应用尤其受到消费者、企业甚至政府的关注。除了对电力供应链的诸多好处之外&#xff0c;物联网能源管理系统还让位于新的智能电网&#xff0c;并有望实现更高的安全性和效率。基于…...

工业4.0和工业物联网如何协同工作

虽然许多公司已经接受了工业物联网&#xff0c;但他们现在必须接受工业4.0对数据驱动的数字化转型的承诺。随着制造业、能源、公用事业和供应链应用迅速采用工业物联网(IIoT)&#xff0c;这些行业的新现实正在形成。工业物联网提供了企业管理数千个活动部件所需的数据类型&…...

NeRF 技术深度解析:原理、局限与前沿应用探索(AI+3D 产品经理笔记 S2E04)

引言&#xff1a;光影的魔法师——神经辐射场概览 在前三篇笔记中&#xff0c;我们逐步揭开了 AI 生成 3D 技术的面纱&#xff1a;从宏观的驱动力与价值&#xff08;S2E01&#xff09;&#xff0c;到主流技术流派的辨析&#xff08;S2E02&#xff09;&#xff0c;再到实用工具的…...

用Ai学习wxWidgets笔记——在 VS Code 中使用 CMake 搭建 wxWidgets 开发工程

声明&#xff1a;本文整理筛选Ai工具生成的内容辅助写作&#xff0c;仅供参考 >> 在 VS Code 中使用 CMake 搭建 wxWidgets 开发工程 下面是一步步指导如何在 VS Code 中配置 wxWidgets 开发环境&#xff0c;包括跨平台设置&#xff08;Windows 和 Linux&#xff09;。…...

《Progressive Transformers for End-to-End Sign Language Production》复现报告

摘要 本文复现了《Progressive Transformers for End-to-End Sign Language Production》一文中的核心模型结构。该论文提出了一种端到端的手语生成方法&#xff0c;能够将自然语言文本映射为连续的 3D 骨架序列&#xff0c;并引入 Counter Decoding 实现动态序列长度控制。我…...

基于React + FastAPI + LangChain + 通义千问的智能医疗问答系统

&#x1f4cc; 文章摘要&#xff1a; 本文详细介绍了如何在前端通过 Fetch 实现与 FastAPI 后端的 流式响应通信&#xff0c;并支持图文多模态数据上传。通过构建 multipart/form-data 请求&#xff0c;配合 ReadableStream 实时读取 AI 回复内容&#xff0c;实现类似 ChatGPT…...

数据通信与计算机网络——数据与信号

主要内容 模拟与数字 周期模拟信号 数字信号 传输减损 数据速率限制 性能 注&#xff1a;数据必须被转换成电磁信号才能进行传输。 一、模拟与数字 数据以及表示数据的信号可以使用模拟或者数字的形式。数据可以是模拟的也可以是数字的&#xff0c;模拟数据是连续的采用…...

(LeetCode 每日一题)3170. 删除星号以后字典序最小的字符串(贪心+栈)

题目&#xff1a;3170. 删除星号以后字典序最小的字符串 思路&#xff1a;贪心栈&#xff0c;时间复杂度0(n)。 对于每一个‘ * ’&#xff0c;优先选最右边的最小字符&#xff0c;才会使最终得到的字符串最小。 用栈&#xff0c;来记录每个字符的位置下标。细节看注释。 C版本…...

Microsoft前后端不分离编程新风向:cshtml

文章目录 什么是CSHTML&#xff1f;基础语法内联表达式代码块控制结构 布局页面_ViewStart.cshtml_Layout.cshtml使用布局 模型绑定强类型视图模型集合 HTML辅助方法基本表单验证 局部视图创建局部视图使用局部视图 高级特性视图组件依赖注入Tag Helpers 性能优化缓存捆绑和压缩…...

【计算机网络】Linux下简单的TCP服务器(超详细)

服务端 创建套接字 &#x1f4bb;我们将TCP服务器封装成一个类&#xff0c;当我们定义出一个服务器对象后需要马上对服务器进行初始化&#xff0c;而初始化TCP服务器要做的第一件事就是创建套接字。 TCP服务器在调用socket函数创建套接字时&#xff0c;参数设置如下&#xff1…...

青少年编程与数学 01-011 系统软件简介 06 Android操作系统

青少年编程与数学 01-011 系统软件简介 06 Android操作系统 一、历史发展二、核心架构1. Linux 内核层 (Linux Kernel)2. 硬件抽象层 (Hardware Abstraction Layer - HAL)3. Native 层 (Native Libraries & Android Runtime)4. Java API 框架层 (Java Framework Layer)5. 应…...

数据类型 -- 字符

在C中&#xff0c;字符型&#xff08;char&#xff09;用于存储单个字符&#xff0c;如字母、数字、符号等。字符型是最基本的数据类型之一&#xff0c;常用于处理文本、字符数组&#xff08;字符串&#xff09;等场景。 1. 基本类型 • char&#xff1a;标准字符类型&#x…...