离线数仓(二)【用户行为日志采集平台搭建】

news2024/10/4 14:26:25

用户行为日志采集平台搭建

1、用户行为日志概述

        用户行为日志的内容,主要包括用户的各项行为信息以及行为所处的环境信息。收集这些信息的主要目的是优化产品和为各项分析统计指标提供数据支撑。收集这些信息的手段通常为埋点

        目前主流的埋点方式,有代码埋点(前端/后端)、可视化埋点全埋点等。

  • 代码埋点是通过调用埋点SDK函数(JavaScript 技术 ),在需要埋点的业务逻辑功能位置调用接口,上报埋点数据。例如,我们对页面中的某个按钮埋点后,当这个按钮被点击时,可以在这个按钮对应的 OnClick 函数里面调用SDK提供的数据发送接口,来发送数据(把用户的行为以 http请求的形式发送到后端)。
  • 可视化埋点只需要研发人员集成采集 SDK,不需要写埋点代码,业务人员就可以通过访问分析平台的“圈选”功能,来“圈”出需要对用户行为进行捕捉的控件,并对该事件进行命名。圈选完毕后,这些配置会同步到各个用户的终端上,由采集 SDK 按照圈选的配置自动进行用户行为数据的采集和发送。
  • 全埋点是通过在产品中嵌入SDK(比如使用神策的埋点SDK),前端自动采集页面上的全部用户行为事件,上报埋点数据,相当于做了一个统一的埋点。然后再通过界面配置哪些数据需要在系统里面进行分析。

目前用的比较多的是全埋点,但是毕竟使用第三方的 SDK 可能出现数据泄露的风险。

2、用户行为日志内容

本项目收集和分析的用户行为信息主要有页面浏览记录、动作记录、曝光记录、启动记录和错误记录。

2.1、页面浏览记录

        页面浏览记录,记录的是访客对页面的浏览行为,该行为的环境信息主要有用户信息、时间信息、地理位置信息、设备信息、应用信息、渠道信息及页面信息等。

  • 用户 id:每个账号分配一个唯一的 id
  • 时间信息:用户跳入页面的时间和跳出的时间,以此来评估用户对该商品的感兴趣程度等等指标
  • 设备信息:获取用户的设备信息,可以用来做广告推荐等

2.2、动作记录

        动作记录,记录的是用户的业务操作行为,该行为的环境信息主要有用户信息、时间信息、地理位置信息、设备信息、应用信息、渠道信息 及动作目标对象信息等。

  • 动作目标对象相关信息,比如用户点击了哪个模块 (优惠券?哪个优惠价)

2.3、曝光记录

        曝光记录,记录的是曝光行为,该行为的环境信息主要有用户信息、时间信息、地理位置信息、设备信息、应用信息、渠道信息及曝光对象信息等。

  • 曝光相关信息:曝光指的是在当前界面展示过的内容

2.4、启动记录

启动记录,记录的是用户启动应用的行为,该行为的环境信息主要有用户信息、时间信息、地理位置信息、设备信息、应用信息、渠道信息、启动类型及开屏广告信息等。

  • 启动类型:用户是点击软件按钮启动还是推送通知启动
  • 开屏广告信息:打开软件时广告界面的广告id

2.5、错误记录

        启动记录,记录的是用户在使用应用过程中的报错行为,该行为的环境信息主要有用户信息、时间信息、地理位置信息、设备信息、应用信息、渠道信息、以及可能与报错相关的页面信息、动作信息、曝光信息和动作信息。

3、用户行为日志格式

        上面我们知道了各种用户行为日志的类型,我们可以发现,有很多记录其实是重复的,比如用户信息、设别信息、渠道信息 ... 存储重复的记录不仅没有意义而且占用磁盘空间,那么应该怎样存储呢?

        我们的日志结构大致可分为两类,一是页面日志,二是启动日志。

3.1、页面日志

        页面日志,以页面浏览为单位,即一个页面浏览记录,生成一条页面埋点日志。一条完整的页面日志包含,一个页面浏览记录,若干个用户在该页面所做的动作记录,若干个该页面的曝光记录,以及一个在该页面发生的报错记录。除上述行为信息,页面日志还包含了这些行为所处的各种环境信息,包括用户信息、时间信息、地理位置信息、设备信息、应用信息、渠道信息等。

{
	"common": {                     -- 环境信息
		"ar": "230000",             -- 地区编码
		"ba": "iPhone",             -- 手机品牌
		"ch": "Appstore",           -- 渠道
		"is_new": "1",              -- 是否首日使用,首次使用的当日,该字段值为1,过了24:00,该字段置为0。
		"md": "iPhone 8",           -- 手机型号
		"mid": "YXfhjAYH6As2z9Iq",  -- 设备id
		"os": "iOS 13.2.9",         -- 操作系统
		"uid": "485",               -- 会员id
		"vc": "v2.1.134"            -- app版本号
	},
	"actions": [{                   -- 动作(事件)
		"action_id": "favor_add",   -- 动作id
		"item": "3",                -- 目标id
		"item_type": "sku_id",      -- 目标类型
		"ts": 1585744376605         -- 动作时间戳
	    }
	],
	"displays": [{                  -- 曝光
			"displayType": "query", -- 曝光类型
			"item": "3",            -- 曝光对象id
			"item_type": "sku_id",  -- 曝光对象类型
			"order": 1,             -- 出现顺序
			"pos_id": 2             -- 曝光位置
		},
		{
			"displayType": "promotion",
			"item": "6",
			"item_type": "sku_id",
			"order": 2,
			"pos_id": 1
		},
		{
			"displayType": "promotion",
			"item": "9",
			"item_type": "sku_id",
			"order": 3,
			"pos_id": 3
		},
		{
			"displayType": "recommend",
			"item": "6",
			"item_type": "sku_id",
			"order": 4,
			"pos_id": 2
		},
		{
			"displayType": "query ",
			"item": "6",
			"item_type": "sku_id",
			"order": 5,
			"pos_id": 1
		}
	],
	"page": {                          -- 页面信息
		"during_time": 7648,           -- 持续时间毫秒
		"item": "3", 	               -- 目标id
		"item_type": "sku_id",         -- 目标类型
		"last_page_id": "login",       -- 上页类型
		"page_id": "good_detail",      -- 页面ID
		"sourceType": "promotion"      -- 来源类型
	},                                 
	"err": {                           --错误
		"error_code": "1234",          --错误码
		"msg": "***********"           --错误信息
	},                                 
	"ts": 1585744374423                --跳入时间戳
}

3.2、启动日志

        启动日志以启动为单位,及一次启动行为,生成一条启动日志。一条完整的启动日志包括一个启动记录,一个本次启动时的报错记录,以及启动时所处的环境信息,包括用户信息、时间信息、地理位置信息、设备信息、应用信息、渠道信息等。

{
  "common": {
    "ar": "370000",
    "ba": "Honor",
    "ch": "wandoujia",
    "is_new": "1",
    "md": "Honor 20s",
    "mid": "eQF5boERMJFOujcp",
    "os": "Android 11.0",
    "uid": "76",
    "vc": "v2.1.134"
  },
  "start": {   
    "entry": "icon",         --icon手机图标  notice 通知   install 安装后启动
    "loading_time": 18803,  --启动加载时间
    "open_ad_id": 7,        --广告页ID
    "open_ad_ms": 3449,    -- 广告总共播放时间
    "open_ad_skip_ms": 1989   --  用户跳过广告时点
  },
"err":{                     --错误
"error_code": "1234",      --错误码
    "msg": "***********"       --错误信息
},
  "ts": 1585744304000    --日志产生的时间
}

4、模拟数据

模拟数据我们直接使用封装好的日志生成 jar 包:

java -jar gmall2020-mock-log-2021-10-10.jar

 我们需要在 hadoop102 和 hadoop103 上都配置好日志数据源,所以为了方便还需要写一个脚本:

#!/bin/bash
for i in hadoop102 hadoop103; do
    echo "========== $i =========="
    ssh $i "cd /opt/module/applog/; java -jar gmall2020-mock-log-2021-10-10.jar >/dev/null 2>&1 &"
done 

        我们在 hadoop102 和 hadoop103 的 /opt/module/applog/log 看到最新生成的日志,这个日志文件是按照时间滚动的


 用户行为日志数据采集模块

1、数据通道

        现在,我们需要把用户行为日志数据通过 Flume 传输到 Kafka 的日志 topic 中。

        上面我们的 hadoop102 和 hadoop103 已经具备了生成日志的能力,之前我们说 flume 是但节点安装,确实没错,但是这里因为我们是两个地方产生日志,如果跨节点传输日志那样效率太低了,所以索性就直接安装两个 flume 即可。

这里我们回顾一下之前学习 flume 的时候讲到的 source ,有

  • taildir:适合用于监听多个实时追加的文件(支持不同目录的不同文件),并且能够实现断点续传
  • netcat:监听 netcat 端口发生过来的内容
  • exec:适用于监控一个实时追加的文件,不能实现断点续传
  • spooling:适合用于同步新文件,支持断点续传,但是它监听的是文件夹而不是文件,不适合对实时追加日志的文件进行监听并同步
  • avro:当需要多个 flume 节点之间传输日志时,之间必须使用 avro sourcce 和 avro sink
  • kafka:kafka source 其实就是一个 Kafka 消费者,从Kafka 的 topic 中读取数据:

还有 channel:

  • file :日志数据缓存在本地磁盘,并且在内存中保存有索引,磁盘中同样保存两份索引来保证读取的速度
  • memory:日志缓存在内存中,读取速度快,但是不安全
  • kafka:实际使用最多的

kafka channel 其实就是把 Event 保存到了 Kafka 集群当中,它支持 3 种结构:

1. 结合 source 和 sink 

2. 只结合 source 

 3. 只结合 sink

还有 sink:

  • hdfs:写出到 hdfs
  • kafka:写出到 kafka,相当于 kafka 消费者
  • avro:写出到 avro 系统(avro 是一个 rpc 数据序列化系统)

为了保证数据的可靠性(以及 Kafak 具有削峰解耦的功能),我们当然是选择 Kafak Channel 作为 channel ,那么对于 Kafak Channel 的三种结构,我们应该如何选择呢?

首先第一种结构 - 结合 source 和 sink,这种结构不可取。因为 Kafka Channel 有一个参数 parseAsFlumeEvent(默认为 true) ,它的意思是把日志数据以 Flume Event  的格式存储到 Kafka,这就包括了 Event Header 和 Event Body。对于离线数仓而言,因为它本来 sink 用的就是 flume 的 sink 从 kafka channel 中读取,它可以把 event 中的 body 解析出来。但是对于实时数仓,flink 是从 kafka 中直接读取数据的,所以它读到的就是包含 header 和 body 的完整 event 数据,而 header 对于实时数仓来说根本没有,所以没有必要存储。

既然 header 不需要存储我们能不能把 parseAsFlumeEvent 设为 false 然后继续使用这种结构呢,我们知道拦截器是在 source 和 channel 之间起作用的,如果不使用 flume event 的形式存储数据就不能使用拦截器,而 channel 和 sink 之间又不能设置拦截器。所以最好的办法就是使用第二种结构 - Kafak Channel 结合 Source 使用,同时设置 parseAsFlumeEvent 参数为 false ,这样存储进 Kafka 的数据就只有 body,虽然没有了 sink,但是我们可以把存储在 Kafak 中的数据当做一个数据源,下游再用一个 Source 读取,这样我们就可以再设置拦截器了。

2、作业脚本配置

编写 flume 配置文件

file_to_kafka.conf

#定义组件
a1.sources = r1
a1.channels = c1

#配置source
a1.sources.r1.type = TAILDIR
a1.sources.r1.filegroups = f1
a1.sources.r1.filegroups.f1 = /opt/module/applog/log/app.*
a1.sources.r1.positionFile = /opt/module/flume-1.9.0/taildir_position.json

#配置channel
a1.channels.c1.type = org.apache.flume.channel.kafka.KafkaChannel
a1.channels.c1.kafka.bootstrap.servers = hadoop102:9092,hadoop103:9092
a1.channels.c1.kafka.topic = topic_log
a1.channels.c1.parseAsFlumeEvent = false

#组装 
a1.sources.r1.channels = c1

测试

# 启动 zookeeper 和 kafka
zk start
kf.sh start
# 开启flume作业
bin/flume-ng agent -n a1 -c conf/ -f job/warehouse/file_to_kafka.conf -Dflume.root.logger=INFO,console
# 开启kafka消费者
bin/kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --topic topic_log
# 开启日志生成器
mklog.sh

运行结果:

至此,flume 的 source -> kafka channel 配置完毕,接下来我们需要在 flume 这里进行一个简单的 ETL 数据清洗,把一些脏数据去除掉,而且这里不能做复杂的拦截器,比如添加多个拦截器,因为flume 毕竟只是一个传递数据的管道,如果这里的 ETL工作太复杂会导致数据堆积在拦截器这里,影响效率。

添加拦截器

引入依赖和打包插件:

    <dependencies>
        <dependency>
            <groupId>org.apache.flume</groupId>
            <artifactId>flume-ng-core</artifactId>
            <version>1.9.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

Json 工具类:

package com.lyh.gmall.utils;

import com.alibaba.fastjson.JSONObject;

public class JSONUtil {

    // 通过异常捕获来校验json是否合法
    public static boolean isJsonValidate(String body) {
        try {
            JSONObject.parseObject(body);
            return true;
        }catch (Exception e){
            return false;
        }
    }
}

自定义拦截器:

package com.lyh.gmall.interceptor;

import com.lyh.gmall.utils.JSONUtil;
import org.apache.flume.Context;
import org.apache.flume.Event;
import org.apache.flume.interceptor.Interceptor;

import java.nio.charset.StandardCharsets;
import java.util.List;

public class ETLInterceptor implements Interceptor {
    @Override
    public void initialize() {

    }

    // 单个事件的拦截器
    @Override
    public Event intercept(Event event) {
        // 1. 获取body当中的数据
        String body = new String(event.getBody(), StandardCharsets.UTF_8);
        // 2. 判断数据是否合法,如果合法直接返回,否则返回 null
        return JSONUtil.isJsonValidate(body)?event:null;
    }

    // 多个事件的拦截器
    @Override
    public List<Event> intercept(List<Event> list) {
        for (int i = 0; i < list.size(); i++) {
            if (intercept(list.get(i)) == null){
                list.remove(i);
                i--;
            }
        }
        return list;
    }

    @Override
    public void close() {

    }

    public static class Builder implements Interceptor.Builder {

        @Override
        public Interceptor build() {
            return new ETLInterceptor();
        }

        @Override
        public void configure(Context context) {

        }
    }
}

打包后会生成两个jar包,选择带依赖的放到 flume 的 lib 目录下,在 flume 作业配置文件中添加以下配置来添加拦截器:

a1.sources.r1.interceptors =  i1
a1.sources.r1.interceptors.i1.type = com.lyh.gmall.interceptor.ETLInterceptor$Builder

测试:

因为 flume 监听的是 applog/log/app-log-xxx.log 文件,所以我们直接 echo 写入来模拟错误日志(不完整的 json 信息): 

可以看到,不合法的 json 数据被过滤掉了,至此,我们的数据采集通道可用了。根据我们的项目架构图可以看到,我们需要在 hadoop102 和 hadoop103 上采集,所以 hadoop103 也许要配置:

flume 采集脚本

#!/bin/bash

case $1 in
"start"){
        for i in hadoop102 hadoop103
        do
                echo " -------- $i flume开始采集 -------"
                ssh $i "nohup /opt/module/flume-1.9.0/bin/flume-ng agent -n a1 -c /opt/module/flume-1.9.0/conf/ -f /opt/module/flume-1.9.0/job/warehouse/file_to_kafka.conf >/dev/null 2>&1 &"
        done
};; 
"stop"){
        for i in hadoop102 hadoop103
        do
                echo " -------- $i flume停止采集-------"
                ssh $i "ps -ef | grep file_to_kafka | grep -v grep |awk  '{print \$2}' | xargs -n1 kill -9 "
        done
};;
esac

总结

        至此,用户行为日志的采集环境搭建好了,只要输入命令 f1.sh start 就可以让在 hadoop102 和 hadoop103 上的 flume开启采集日志了。接下来就是业务数据的采集了。

        这一部分还算简单,对于 flume 的操作无非就是拦截器的编写,逻辑也没多复杂,flume 的 source 使用了 taildir 监听由脚本不断生成的日志文件,channel 使用了 Kafka source ,sink 估计不会采用 flume 的 sink。

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

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

相关文章

力扣题目训练(15)

2024年2月8日力扣题目训练 2024年2月8日力扣题目训练507. 完美数520. 检测大写字母521. 最长特殊序列 Ⅰ221. 最大正方形237. 删除链表中的节点115. 不同的子序列 2024年2月8日力扣题目训练 2024年2月8日第十五天编程训练&#xff0c;今天主要是进行一些题训练&#xff0c;包括…

柚见(伙伴匹配系统)第六期

开发主页 开发主页&#xff08;默认推荐和自己兴趣相当的用户&#xff09;优化主页的性能&#xff08;缓存 定时任务 分布式锁&#xff09; 前端recommend 最简单&#xff1a;直接 list 列表 cv searchResult页面的代码 修改 后端接口 数据内容下边距修改 提取用户信息卡…

沁恒CH32V30X学习笔记06---串口dma接收+空闲中断组合接收数据

DMA 控制器提供 18 个通道,其中 DMA1 包含 7 个通道,DMA2 包含 11 个通道,每个通 道对应多个外设请求,通过设置相应外设寄存器中对应 DMA 控制位 通道映射 dma1 dma2 示例代码 bsp_usart_it.c /** bsp_usart_it.c** Created on: 2024年2月18日* Author: admin*/…

蓝桥杯Java组备赛(四)

高精度加法 import java.math.BigInteger; import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);BigInteger a,b;a sc.nextBigInteger();b sc.nextBigInteger();System.out.println(a.add(b));sc.cl…

代码随想录算法训练营第十七天 | 110.平衡二叉树,257. 二叉树的所有路径,404.左叶子之和 [二叉树篇]

代码随想录算法训练营第十七天 LeetCode 110.平衡二叉树题目描述思路参考代码 LeetCode 257. 二叉树的所有路径题目描述思路参考代码 LeetCode 404.左叶子之和题目描述思路参考代码 LeetCode 110.平衡二叉树 题目链接&#xff1a;110.平衡二叉树 文章讲解&#xff1a;代码随想录…

可转债和股票有哪些区别?可转债和股票哪个好?

可转债&#xff0c;全称可转换债券&#xff0c;指的是持有者可以在特定时期、按特定条件&#xff0c;将其转换为特定数量的另一种证券的债券。这种债券可以转换成公司的普通股票。 如果债券持有人看好发债公司股票增值潜力&#xff0c;在宽限期之后可以行使转换权&#xff0c;…

SOLIDWORKS PDM—中央卡列表

SOLIDWORKS产品数据管理 (PDM) 解决方案可帮助您控制设计数据&#xff0c;并且从本质上改进您的团队就产品开发进行管理和协作的方式。使用 SOLIDWORKS PDM Professional&#xff0c;您的团队能够&#xff1a;1. 安全地存储和索引设计数据以实现快速检索&#xff1b;2. 打消关于…

条码扫描器

介绍 条码扫描器&#xff0c;又称为条码阅读器、条码扫描枪、条形码扫描器、条形码扫描枪及条形码阅读器。它是用于读取条码所包含信息的阅读设备&#xff0c;利用光学原理&#xff0c;把条形码的内容解码后通过数据线或者无线的方式传输到电脑或者别的设备。广泛应用于超市、物…

2024年腾讯云4核8G12M轻量应用服务器测评,2月更新

4核8G服务器支持多少人同时在线访问&#xff1f;阿腾云的4核8G服务器可以支持20个访客同时访问&#xff0c;关于4核8G服务器承载量并发数qps计算测评&#xff0c;云服务器上运行程序效率不同支持人数在线人数不同&#xff0c;公网带宽也是影响4核8G服务器并发数的一大因素&…

搜维尔科技:分析OptiTrack光学动作捕捉应用领域!

虚拟制作 当今虚拟制作阶段低延迟、超精确摄像机跟踪的事实上的标准。 用于运动科学的 OptiTrack OptiTrack 系统提供世界领先的测量精度和简单易用的工作流程&#xff0c;为研究人员和生物力学师的研究提供理想的 3D 跟踪数据。对所有主要数字测力台、EMG 和模拟设备的本机即…

Kernelized Correlation Filters KCF算法原理详解(阅读笔记)(待补充)

KCF 目录 KCF预备知识1. 岭回归2. 循环移位和循环矩阵3. 傅里叶对角化4. 方向梯度直方图&#xff08;HOG&#xff09; 正文1. 线性回归1.1. 岭回归1.2. 基于循环矩阵获取正负样本1.3. 基于傅里叶对角化的求解 2. 使用非线性回归对模型进行训练2.1. 应用kernel-trick的非线性模型…

机构如何搭建一个在线课程教学平台?

随着数字化教育的兴起&#xff0c;越来越多的教育机构开始考虑建立自己的在线课程教学平台。这一趋势不仅顺应了时代的发展&#xff0c;而且为教育行业带来了诸多便利和优势。构建一个在线教学平台可以帮助机构拓宽服务范围、提升教学质量、增强学生体验&#xff0c;并且能够有…

【机器学习】数据清洗——基于Pandas库的方法删除重复点

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;机器学习 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进…

《Solidity 简易速速上手小册》第6章:优化 Gas 消耗和性能(2024 最新版)

文章目录 6.1 理解 Gas 和交易成本6.1.1 基础知识解析更深入的理解优化的关键点 6.1.2 重点案例&#xff1a;优化合约以降低 Gas 成本案例 Demo&#xff1a;创建一个经济高效的财务管理合约案例代码FinancialManagementContract.sol 测试和验证拓展功能 6.1.3 拓展案例 1&#…

【plt.pie绘制饼图】:从入门到精通,只需一篇文章!【Matplotlib可视化】

【&#x1f4ca;plt.pie绘制饼图】&#xff1a;从入门到精通&#xff0c;只需一篇文章&#xff01;【Matplotlib可视化】&#xff01; 利用Matplotlib进行数据可视化示例 &#x1f335;文章目录&#x1f335; &#x1f3a8; 一、饼图初探&#xff1a;基本概念与用途&#x1f4a…

软件测试系列:移动端安卓APP测试必备之ADB命令 (二)

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

AD24-Objects元素、特殊复制粘贴、多根走线、自动布线、泪滴

一、Objects元素的隐藏与显示 1、Altium Transparent 2D与Altium Standard 2D的区别 1) Altium Transparent 2D 2) Altium Standard 2D 二、特殊复制粘贴 1、如何把元件带位号、带网络从当前PCB调用到另外的PCB中 三、多根走线与多根走线设置 四、Active Route 的自动布线辅助…

RSA加密,解密,加签及验签

目录 1.说明 2.加密和加签的区别 3.后端加密&#xff0c;解密&#xff0c;加签及验签示例 4.前端加密&#xff0c;解密&#xff0c;加签及验签示例 5.前端加密&#xff0c;后端解密&#xff0c;前端加签&#xff0c;后端验签 6.注意事项 1.说明 RSA算法是一种非对称加密…

压缩感知——革新数据采集的科学魔法

引言&#xff1a; 在数字时代&#xff0c;数据以及数据的收集和处理无处不在。压缩感知(Compressed Sensing, CS)是一种新兴的数学框架&#xff0c;它挑战了我们传统上对数据采集和压缩的看法&#xff0c;给医学图像、天文观测、环境监测等领域带来了颠覆性的影响。但到底什么…

白话微机:5.解释串行接口以及一些考研面试问题

一. 前言&#xff08;回顾世界观&#xff09; 很久很久以前&#xff0c;有这样一个世界&#xff0c;这个世界有着现实世界一样的元素&#xff1a;那里的人又有一个别的名字叫做“数据”&#xff0c;人有0有1&#xff1b;人们也有住房&#xff0c;这些住房在这个世界叫做“存储器…