1-Flume中agent的source

Flume(1.11.0版本)

简介

概述

  1. Flume本身是由Cloudera公司开发的后来贡献给了Apache的一套针对日志数据进行收集(collecting)、汇聚(aggregating)和传输(moving)的机制

  2. Flume本身提供了简单且灵活的结构来完成日志数据的传输

    Flume结构

  3. Flume有两大版本:

    1. Flume0.X:又称之为Flume-og,依赖于Zookeeper部署,需要提供的格式文件相对复杂,所以现在市面上已经不使用了
    2. Flume1.X:又称之为Flume-ng,不依赖于Zookeeper部署,需要提供的格式文件结构明确且简单,所以是现在流通的版本

基本概念

  1. Event

    1. Flume会将收集到的每一条日志封装成一个Event

    2. Event本质上就是一个json串,即Flume会将收集到的日志封装成json的形式,Event中固定的包含两部分:headers和body

      {"headers":{},"body":""}
      
  2. Agent:Flume流动模型的基本组成结构,至少包含3部分

    1. Source:从数据源采集数据 - collecting
    2. Channel:临时存储数据 - aggregating
    3. Sink:将数据写出到目的地 - moving

流动模型

  1. 单级流动

    Flume结构

  2. 多级流动:又称之为串联流动

    多级流动

  3. 扇入流动:又称之为并联流动、聚集流动

    扇入流动

  4. 扇出流动:又称之为复用流动

    扇出流动

  5. 复杂流动:按照需求将多个流动进行组合,那么就是复杂流动

参数解释

参数解释
--name或者-n指定要运行的agent的名字
--conf或者-cFlume的原生配置
--conf-file或者-f执行的文件
-D指定运行其他的参数
flume.root.logger指定日志的打印级别,级别分为INFOWARNERROR,可以指定打印位置consolelogfile

Source

NetCat TCP Source

  1. Netcat TCP Source监听TCP请求,在使用的时候需要监听指定的主机和端口,从这个指定主机的指定端口来接收TCP请求,并且将TCP请求内容作为日志来进行收集

  2. 默认情况下,每一条数据大小不能超过512B,可以通过参数max-line-length来修改

    1. 在Flume中,所有的流动模型,不是通过代码来指定,而是通过格式文件来配置,所以实际过程中,往往会要求格式文件存放在统一的位置上。上课过程中,统一要求将格式文件放到/opt/software/flume-1.11.0/data

      cd /opt/software/flume-1.11.0/
      mkdir data
      cd data
      
    2. 编辑格式文件,文件名和后缀名可以自己定义 properties文件的 key = value 格式配置在vim会有颜色上的区分,便于阅读。

      vim basic.propertie
      

      在文件中添加

      # 给Agent起名   a1就是这个agent的名字
      # 给Source起名
      # 如果有多个Source,那么名字之间用空格隔开
      a1.sources = s1
      # 给Channel起名
      a1.channels = c1
      # 给Sink起名
      a1.sinks = k1# 配置Source
      a1.sources.s1.type = netcat
      a1.sources.s1.bind = 0.0.0.0
      a1.sources.s1.port = 8090# 配置Channel
      a1.channels.c1.type = memory
      a1.channels.c1.capacity = 1000
      a1.channels.c1.transactionCapacity = 1000# 配置Sink
      a1.sinks.k1.type = logger# 将Source和Channel绑定
      a1.sources.s1.channels = c1
      # 将Sink和Channel绑定
      a1.sinks.k1.channel = c1
      
    3. 执行

      flume-ng agent --name a1 --conf $FLUME_HOME/conf --conf-file basic.properties -Dflume.root.logger=INFO,console
      
    4. 复制窗口之后,发送TCP请求

      nc hadoop01 8090
      

Exec Source

  1. Exec Source运行指定命令,监听命令结果,将命令结果作为日志进行收集

  2. 案例:监听指定文件,如果文件中新添了数据,那么自动收集这个文件中的数据

    1. 构建空文件

      touch /opt/software/flume-1.11.0/data/a.txt
      
    2. 监听这个文件,如果这个文件中新添了数据,自动收集数据作为日志

      vim execsource.properties
      

      在文件中添加

      a1.sources = s1
      a1.channels = c1
      a1.sinks = k1# 配置Exec Source
      # Source的类型
      a1.sources.s1.type = exec
      # 监听指定的命令
      a1.sources.s1.command = tail -F /opt/software/flume-1.11.0/data/a.txt
      # 指定命令的脚本类型
      a1.sources.s1.shell = /bin/sh -ca1.channels.c1.type = memorya1.sinks.k1.type = loggera1.sources.s1.channels = c1
      a1.sinks.k1.channel = c1
      
    3. 执行命令

      flume-ng agent -n a1 -c $FLUME_HOME/conf -f execsource.properties -Dflume.root.logger=INFO,console
      
    4. 在新窗口中追加数据

      echo "testing" >> /opt/software/flume-1.11.0/data/a.txt
      echo "exec" >> /opt/software/flume-1.11.0/data/a.txt
      

      AVRO Source

      1. AVRO Source接收被AVRO序列化之后的数据,结合AVRO Sink,可以实现复杂的流动模型

      2. 案例

        1. 编辑文件

          cd /opt/software/flume-1.11.0/data/
          vim avrosource.properties 
          

          在文件中添加

          a1.sources = s1           
          a1.channels = c1
          a1.sinks = k1# 配置AVRO Source
          # 类型必须是avro
          a1.sources.s1.type = avro
          # 监听的主机
          a1.sources.s1.bind = 0.0.0.0
          # 监听的端口号
          a1.sources.s1.port = 6666a1.channels.c1.type = memorya1.sinks.k1.type = loggera1.sources.s1.channels = c1
          a1.sinks.k1.channel = c1
          
        2. 启动

          flume-ng agent -n a1 -c $FLUME_HOME/conf -f avrosource.properties -Dflume.root.logger=INFO,console
          
        3. 在新窗口中启动AVRO客户端

          flume-ng avro-client -H hadoop01 -p 6666 -F a.txt
          

      Spooling Directory Source

      1. 监听指定的目录,如果目录中产生了新的文件,那么自动的将新文件中的内容收集起来

      2. 默认情况下,这个文件如果被收集了,那么文件的后缀就是.COMPLETED

      3. 案例

        1. 创建目录

          mkdir /opt/flume_data
          
        2. 编辑文件

          vim spooldirsource.properties
          

          在文件中添加

          a1.sources = s1
          a1.channels = c1
          a1.sinks = k1# 配置Spooling Directory Source
          # 类型必须是spooldir
          a1.sources.s1.type = spooldir
          # 监听的目录
          a1.sources.s1.spoolDir = /opt/flume_data
          # 被收集过的文件后缀
          # 利用这条规则,可以过滤掉一部分不需要收集的文件
          a1.sources.s1.fileSuffix = .finisheda1.channels.c1.type = memorya1.sinks.k1.type = loggera1.sources.s1.channels = c1
          a1.sinks.k1.channel = c1
          
        3. 执行

          flume-ng agent -n a1 -c $FLUME_HOME/conf -f spooldirsource.properties -Dflume.root.logger=INFO,console
          

      Taildir Source

      1. 可以用于监听一个或者一组文件,如果被监听的文件中添加了新数据,那么新添的数据会被自动收集

      2. Exec Source需要通过指定tail -F命令才能监听指定文件,Spooling Directory Source监听指定的目录,并不能确定文件中是否新添了数据

      3. 不同于Exec Source的地方在于,Taildir Source不需要指定命令,还可以监控一类文件,且Taildir Source通过记录偏移量实现断点续传效果

      4. 偏移量通过属性positionFile来决定,默认是~/.flume/taildir_position.json

      5. 需要注意的是,Taildir Source不支持在Windows中使用

      6. 案例:监听flume_data目录下所有的log和txt文件,如果文件被添加新数据,那么自动收集

        1. 编辑文件

          vim taildirsource.properties
          
        2. 在文件中添加

          a1.sources = s1
          a1.channels = c1
          a1.sinks = k1# 配置Taildir Source
          # 类型必须是TAILDIR
          a1.sources.s1.type = TAILDIR
          # 监听的一组文件的组名
          a1.sources.s1.filegroups = f1 f2
          # 文件组中的要监听的文件
          a1.sources.s1.filegroups.f1 = /opt/flume_data/.*log.*
          a1.sources.s1.filegroups.f2 = /opt/flume_data/.*txt.*
          # 偏移量的存储位置
          a1.sources.s1.positionFile = /opt/flume_data/taildir_position.jsona1.channels.c1.type = memorya1.sinks.k1.type = loggera1.sources.s1.channels = c1
          a1.sinks.k1.channel = c1
          
        3. 执行

          flume-ng agent -n a1 -c $FLUME_HOME/conf -f taildirsource.properties -Dflume.root.logger=INFO,console
          

      Sequence Generator Source

      1. 序列产生器,从0开始递增到totalEvents,默认情况下totalEvents的值Long.MAX_VALUE

      2. 实际过程中,会利用这个Source测试流动模型是否搭建成功

      3. 案例

        a1.sources = s1
        a1.channels = c1
        a1.sinks = k1# 配置Sequence Generator Source
        # 类型必须是seq
        a1.sources.s1.type = seq
        # 最大值
        a1.sources.s1.totalEvents = 100a1.channels.c1.type = memorya1.sinks.k1.type = loggera1.sources.s1.channels = c1
        a1.sinks.k1.channel = c1
        

      HTTP Source

      1. 接收HTTP请求,并且将请求内容作为日志进行收集

      2. 只能接收GET和POST请求,其中GET请求接收只能用于实验,实际过程中使用HTTP Source来接收POST请求

      3. 案例

        1. 在文件中添加

          a1.sources = s1
          a1.channels = c1
          a1.sinks = k1# 配置HTTP Source
          # 类型必须是http
          a1.sources.s1.type = http
          # 监听端口
          a1.sources.s1.port = 8888a1.channels.c1.type = memorya1.sinks.k1.type = loggera1.sources.s1.channels = c1
          a1.sinks.k1.channel = c1
          
        2. 启动Flume

        3. 发送POST请求

          curl -X POST -d '[{"headers":{"class":"flume"},"body":"welcome~~~"}]' http://hadoop01:8888
          

      Custom Source

      1. Flume支持用户自定义Source。Flume针对Source提供了顶级接口Source,但是实际过程中,并不是实现Source接口,而是实现子接口之一:
        1. EventDrivenSource:事件驱动Source,本身是一个被动型Source,需要自己定义线程来获取数据以及封装数据
        2. PollableSource:拉取Source,本身是一个主动型Source,提供了线程来获取数据,只需要考虑数据怎么封装即可
      2. 由于在自定义Source的时候,还需要考虑获取格式文件中的参数值,所以还需要实现Configurable接口
      3. 实际过程中,考虑到要覆盖的方法比较多,所以继承AbstractSource
      pom依赖
      <!--Flume核心包-->
      <dependency><groupId>org.apache.flume</groupId><artifactId>flume-ng-core</artifactId><version>1.11.0</version>
      </dependency>
      <!--Flume开发包-->
      <dependency><groupId>org.apache.flume</groupId><artifactId>flume-ng-sdk</artifactId><version>1.11.0</version>
      </dependency>
      <!--Flume配置包-->
      <dependency><groupId>org.apache.flume</groupId><artifactId>flume-ng-configuration</artifactId><version>1.11.0</version>
      </dependency>
      
      自定义EventDrivenSource
      代码
      import org.apache.flume.Context;
      import org.apache.flume.Event;
      import org.apache.flume.EventDrivenSource;
      import org.apache.flume.channel.ChannelProcessor;
      import org.apache.flume.conf.Configurable;
      import org.apache.flume.event.EventBuilder;
      import org.apache.flume.source.AbstractSource;import java.util.HashMap;
      import java.util.Map;
      import java.util.concurrent.ExecutorService;
      import java.util.concurrent.Executors;// 自定义代码实现Sequence Generator Source,加深理解
      public class AuthDrivenSource extends AbstractSource implements EventDrivenSource, Configurable {
      private long start;
      private long end;
      private long step;
      private ExecutorService es;// 获取参数值
      @Override
      public void configure(Context context) {// 3 -> +4// 获取起始值// 如果用户没有指定,那么默认从0开始递增start = context.getLong("start", 0L);// 获取结束值// 如果不指定,递增到Long.MAX_VALUEend = context.getLong("end", Long.MAX_VALUE);// 获取步长// 如果不指定,那么默认每次递增1step = context.getLong("step", 1L);// 保证数据的合理性if (start > end || step < 1)throw new IllegalArgumentException();
      }// 启动Source
      @Override
      public synchronized void start() {// 线程池中准备5个线程es = Executors.newFixedThreadPool(5);// 获取ChannelProcessorChannelProcessor cp = this.getChannelProcessor();// 提交任务es.submit(new Add(start, end, step, cp));
      }// 结束Source
      @Override
      public synchronized void stop() {if (es != null) es.shutdown();
      }}// 自增
      class Add implements Runnable {private final long start;
      private final long end;
      private final long step;
      private final ChannelProcessor cp;public Add(long start, long end, long step, ChannelProcessor cp) {this.start = start;this.end = end;this.step = step;this.cp = cp;
      }@Override
      public void run() {for (long i = start; i < end; i += step) {// 封装headers// 在headers中记录了数据产生的时间Map<String, String> headers = new HashMap<>();headers.put("time", String.valueOf(System.currentTimeMillis()));// 封装bodybyte[] body = String.valueOf(i).getBytes();// 将数据封装成EventEvent e = EventBuilder.withBody(body, headers);// 将Event传递给Channel来存储cp.processEvent(e);}
      }
      }
      
      1. 将程序打成jar包(要求是JDK1.8,好多框架还不支持17版本),上传到Flume安装目录的lib目录下

        cd /opt/software/flume-1.11.0/lib/
        rz
        
      2. 回到格式文件目录下,编辑文件

        cd /opt/software/flume-1.11.0/data/
        vim authdrivensource.properties
        

        在文件中添加

        a1.sources = s1
        a1.channels = c1
        a1.sinks = k1# 配置自定义EventDrivenSource
        # 类型必须是类的全路径名
        a1.sources.s1.type = com.fesco.source.AuthDrivenSource
        # 起始值
        a1.sources.s1.start = 10
        # 结束值
        a1.sources.s1.end = 100
        # 步长
        a1.sources.s1.step = 5a1.channels.c1.type = memorya1.sinks.k1.type = loggera1.sources.s1.channels = c1
        a1.sinks.k1.channel = c1
        
      3. 启动Flume

      自定义PollableSource
      代码
      import org.apache.flume.Context;
      import org.apache.flume.Event;
      import org.apache.flume.PollableSource;
      import org.apache.flume.channel.ChannelProcessor;
      import org.apache.flume.conf.Configurable;
      import org.apache.flume.event.EventBuilder;
      import org.apache.flume.source.AbstractSource;import java.util.ArrayList;
      import java.util.HashMap;
      import java.util.List;
      import java.util.Map;public class AuthPollableSource extends AbstractSource implements PollableSource, Configurable {
      private long min;
      private long max;
      private long step;// 获取配置
      @Override
      public void configure(Context context) {this.min = context.getLong("min", 0L);this.max = context.getLong("max", Long.MAX_VALUE);this.step = context.getLong("step", 1L);if (min > max || step < 1)throw new IllegalArgumentException();
      }// 封装数据,写出数据
      @Override
      public Status process() {// 定义List来临时存储数据List<Event> events = new ArrayList<>();// 获取ChannelProcessorChannelProcessor cp = this.getChannelProcessor();for (long i = min; i < max; i += step) {// 封装headersMap<String, String> headers = new HashMap<>();headers.put("timestamp", String.valueOf(System.currentTimeMillis()));// 封装bodybyte[] body = String.valueOf(i).getBytes();// 封装EventEvent e = EventBuilder.withBody(body, headers);events.add(e);// 每50条数据写一次if (events.size() >= 50) {// 写出数据。这个方法一次写出多个cp.processEventBatch(events);// 清空集合events.clear();}}return Status.READY;
      }// PollableSource主动提供线程来获取数据
      // 如果线程暂时没有获取到数据,那么线程会临时休眠
      // 这个方法就是控制线程的休眠时间,单位是毫秒
      @Override
      public long getBackOffSleepIncrement() {return 1000;
      }@Override
      public long getMaxBackOffSleepInterval() {return 10000;
      }
      }
      
      1. 打成jar包,上传到lib目录下

        cd ../lib
        rz
        
      2. 回到格式文件目录下,编辑文件

        cd ../data/
        vim authpollablesource.properties
        

        在文件中添加

        a1.sources = s1
        a1.channels = c1
        a1.sinks = k1# 配置自定义PollableSource
        # 类型必须是类的全路径名
        a1.sources.s1.type = com.fesco.source.AuthPollableSource   //注意自己的全类名
        # 起始值
        a1.sources.s1.min = 10
        # 结束值
        a1.sources.s1.max = 1000
        # 步长
        a1.sources.s1.step = 5a1.channels.c1.type = memorya1.sinks.k1.type = loggera1.sources.s1.channels = c1
        a1.sinks.k1.channel = c1
        

      cd …/data/
      vim authpollablesource.properties

      
      在文件中添加```properties
      a1.sources = s1
      a1.channels = c1
      a1.sinks = k1# 配置自定义PollableSource
      # 类型必须是类的全路径名
      a1.sources.s1.type = com.fesco.source.AuthPollableSource   //注意自己的全类名
      # 起始值
      a1.sources.s1.min = 10
      # 结束值
      a1.sources.s1.max = 1000
      # 步长
      a1.sources.s1.step = 5a1.channels.c1.type = memorya1.sinks.k1.type = loggera1.sources.s1.channels = c1
      a1.sinks.k1.channel = c1
      
      1. 启动Flume

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

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

相关文章

jQuery 选择器--获取元素

文章目录 1 jQuery 基础选择器2 层级选择器3 隐式迭代(重要)4 jQuery 筛选选择器5 jQuery 筛选方法(重点)案例--下拉菜单 6 jQuery 排他思想*案例--左右Tab栏切换 7 jQuery 链式编程 1 jQuery 基础选择器 2 层级选择器 3 隐式迭代(重要) 示例&#xff1a; 4 jQuery 筛选选择器…

流畅的 Python 第二版(GPT 重译)(十二)

第五部分&#xff1a;元编程 第二十二章&#xff1a;动态属性和属性 属性的关键重要性在于&#xff0c;它们的存在使得将公共数据属性作为类的公共接口的一部分完全安全且确实可取。 Martelli、Ravenscroft 和 Holden&#xff0c;“为什么属性很重要” 在 Python 中&#xff0…

前端如何一次处理十万条数据的渲染

前端如何一次处理十万条数据的渲染 一、下载第三方插件二、在入口文件引入三、示例 一、下载第三方插件 npm install --save el-table-infinite-scroll二、在入口文件引入 import ElTableInfiniteScroll from "el-table-infinite-scroll"; Vue.use(ElTableInfinite…

docker 配置国内阿里镜像源

在/etc/docker/目录下新建daemon.json文件 在文件中写入 {"registry-mirrors": ["https://jmphwhtw.mirror.aliyuncs.com"] } 以管理员身份运行命令 systemctl daemon-reload systemctl restart docker

项目中如何进行限流(限流的算法、实现方法详解)

❤ 作者主页&#xff1a;李奕赫揍小邰的博客 ❀ 个人介绍&#xff1a;大家好&#xff0c;我是李奕赫&#xff01;(&#xffe3;▽&#xffe3;)~* &#x1f34a; 记得点赞、收藏、评论⭐️⭐️⭐️ &#x1f4e3; 认真学习!!!&#x1f389;&#x1f389; 文章目录 限流的算法漏…

MFO-CNN-LSTM多输入分类预测|飞蛾扑火算法优化的卷积-长短期神经网络|Matlab

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、算法介绍&#xff1a; 四、完整程序下载&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码基于Matlab平台编译&am…

最新优质电商API接口,附带Python教程

接口信息 API 接口是应用程序编程接口&#xff08;Application Programming Interface&#xff09;的缩写。 它是一组定义了软件组件之间如何交互和通信的规则和规范。简单来说&#xff0c;API 接口就是让不同的软件系统能够相互“交流”和“合作”的桥梁。打个比方&#xff…

onlyoffice第一次打开特别慢的问题优化

分析问题 上传oss 找到fonts上传到oss中 更改nginx配置 找到nginx所在位置 找到ds-docservice.conf #### onlyoffice二次开发&#xff0c;优化fonts请求速度的问题 location ~* /8.0.0-99/fonts(.*){return https://xxxx-xxxx.cos.ap-shanghai.myqcloud.com/fonts$1?…

jQuery 基础

文章目录 1. jQuery 概述1.1 JavaScript 库1.2 jQuery 概念1.3 jQuery 优点 2. jQuery 基本使用2.1 下载2.2 使用步骤2.3 jQuery 的入口函数2.4 jQuery 的顶级对象 $2.5 DOM 对象和 jQuery 对象DOM 对象和 jQuery 对象相互转换方法 1. jQuery 概述 1.1 JavaScript 库 1.2 jQue…

一篇文章带你了解知乎热门话题的撰写技巧

在当今信息高速发展的时代&#xff0c;人们越来越依赖网络获取知识。而知乎作为一个知识分享和知识传播的平台&#xff0c;吸引了大量用户的关注和参与。那么&#xff0c;如何在知乎上撰写一篇引人注目的文章呢&#xff1f;接下来&#xff0c;腾轩科技传媒探讨一下知乎文章的撰…

活动回顾 | 走进华为向深问路,交流数智办公新体验

3月20日下午&#xff0c;“企业数智办公之走进华为”交流活动在华为上海研究所成功举办。此次活动由上海恒驰信息系统有限公司主办&#xff0c;华为云计算技术有限公司和上海利唐信息科技有限公司协办&#xff0c;旨在通过对企业数字差旅和HR数智化解决方案的交流&#xff0c;探…

MySQL之基本操作与用户授权

一 基本操作 1 SQL分类 数据库&#xff1a;database 表&#xff1a;table&#xff0c;行&#xff1a;row 列&#xff1a;column 索引&#xff1a;index 视图&#xff1a;view 存储过程&#xff1a;procedure 存储函数&#xff1a;function 触发器&#xff1a;trigger 事…

【强化学习公式推导】状态价值函数与动作价值函数贝尔曼期望方程,贝尔曼最优方程推导过程

【强化学习公式推导】状态价值函数与动作价值函数贝尔曼期望方程&#xff0c;贝尔曼最优方程推导过程 1.回报 2.当前时刻的回报与下一时刻回报的关系 3.状态价值函数 4.动作价值函数 5.状态价值函数与动作状态价值函数的关系 6.贝尔曼期望方程 7.状态价值函数的贝尔…

迷宫(蓝桥杯)——DFS和BFS

迷宫 题目描述 下图给出了一个迷宫的平面图&#xff0c;其中标记为 1 的为障碍&#xff0c;标记为 0 的为可以通行的地方。 010000 000100 001001 110000迷宫的入口为左上角&#xff0c;出口为右下角&#xff0c;在迷宫中&#xff0c;只能从一个位置走到这 个它的上、下、左…

[云] vmware: host: net: Net.CoaleseDefaultOn

https://communities.vmware.com/t5/Storage-Performance/Advanced-Networking-Performance-Options/ta-p/2792649 在vsphere client下的路径是&#xff1a; 选择使用的host -> 右键setting->configure-> system->advanced system setting->edit->Net.Coales…

微信小程序开发之创建一个自己的项目和项目目录下各个文件的了解

1、小程序开发工具基础 &#xff08;1&#xff09;菜单栏&#xff1a;可以对开发工具进行一些简单的设置&#xff0c;还可以在帮助一行获取学习相关api文档 &#xff08;2&#xff09;模拟器显示栏&#xff1a;每当我们在进行便写好代码之后&#xff0c;通过编译可以在模拟显示…

华为ensp中ospf基础 原理及配置命令(详解)

CSDN 成就一亿技术人&#xff01; 作者主页&#xff1a;点击&#xff01; ENSP专栏&#xff1a;点击&#xff01; CSDN 成就一亿技术人&#xff01; ————前言———— OSPF 的全称是 Open Shortest Path First&#xff0c;意为“开放式最短路径优先”。是一种内部网关协…

【算法刷题day3】Leetcode: 203.移除链表元素、707.设计链表、 206.反转链表

链表基础知识 分类&#xff1a; 单链表、双链表、循环连链表 存储方式&#xff1a; 链表中的节点在内存中不是连续分布的 &#xff0c;而是散乱分布在内存中的某地址上&#xff0c;分配机制取决于操作系统的内存管理。 链表的定义&#xff1a; struct ListNode{int val; //节…

【如何安装odl: 1.0.0.dev0】

【如何安装odl: 1.0.0.dev0】 ODL官网 pip install odl可能容易报错&#xff0c;建议使用下述命令安装 pip install https://github.com/odlgroup/odl/archive/master.zip检查是否安装成功 conda list

聊聊车载以太网PMA测试解决方案

自2013年起&#xff0c;车载以太网技术日益成熟&#xff0c;在电子电气系统中应用越来越广泛&#xff0c;因此逐渐有很多主机厂和供应商加入到车载以太网技术的开发应用中&#xff0c;同时对传输速率的要求逐步提高&#xff0c;产生了传输速率更高的车载以太网技术&#xff0c;…