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

为什么我推荐你使用 systemd timer 替代 cronjob?

概述

前几天在使用 Terraform + cloud-init 批量初始化我的实验室 Linux 机器。正好发现有一些定时场景需要使用到 cronjob, 进一步了解到 systemd timer 完全可以替换 cronjob, 并且 systemd timer 有一些非常有趣的功能。

回归话题:为什么我推荐你使用 systemd timer 替代 cronjob? 因为相比 cronjob, systemd timer 有这些优势:

  • 可以覆盖 cronjob 的所有功能
  • 统一日志收集到 systemd 日志
  • 针对时间精确度更详细的配置项
  • 除了定时场景,还支持基于 event 的触发
  • 相比 cronjob 更灵活的语法
  • 更丰富的使用/运维命令集

接下来我们一一介绍。

首先我们通过系统自带的 timer 来熟悉这个新玩意。

系统自带的 timer

当 Ubuntu 或任何基于 systemd 的发行版安装在一个新系统上时,它会创建几个 timer,作为任何 Linux 主机后台的系统维护程序的一部分。这些 timer 会触发普通维护任务所需的事件,比如更新系统数据库、清理临时目录、切割日志文件等等。

我们使用systemctl status *timer命令列出我的主机上的所有 timer:

casey@casey-Virtual-Machine:~$ systemctl status *timer
● plocate-updatedb.timer - Update the plocate database dailyLoaded: loaded (/lib/systemd/system/plocate-updatedb.timer; enabled; vendor preset: enabled)Active: active (waiting) since Tue 2023-04-04 16:49:49 CST; 19s agoTrigger: Wed 2023-04-05 00:40:16 CST; 7h leftTriggers: ● plocate-updatedb.service4 月 04 16:49:49 casey-Virtual-Machine systemd[1]: Started Update the plocate database daily.● fwupd-refresh.timer - Refresh fwupd metadata regularlyLoaded: loaded (/lib/systemd/system/fwupd-refresh.timer; enabled; vendor preset: enabled)Active: active (waiting) since Tue 2023-04-04 16:49:49 CST; 19s agoTrigger: Wed 2023-04-05 01:54:51 CST; 9h leftTriggers: ● fwupd-refresh.service4 月 04 16:49:49 casey-Virtual-Machine systemd[1]: Started Refresh fwupd metadata regularly.● update-notifier-motd.timer - Check to see whether there is a new version of Ubuntu availableLoaded: loaded (/lib/systemd/system/update-notifier-motd.timer; enabled; vendor preset: enabled)Active: active (waiting) since Tue 2023-04-04 16:49:50 CST; 19s agoTrigger: Sat 2023-04-08 03:19:02 CST; 3 days leftTriggers: ● update-notifier-motd.service4 月 04 16:49:50 casey-Virtual-Machine systemd[1]: Started Check to see whether there is a new version of Ubuntu available.● fstrim.timer - Discard unused blocks once a weekLoaded: loaded (/lib/systemd/system/fstrim.timer; enabled; vendor preset: enabled)Active: active (waiting) since Tue 2023-04-04 16:49:49 CST; 19s agoTrigger: Tue 2023-04-04 17:58:23 CST; 1h 8min leftTriggers: ● fstrim.serviceDocs: man:fstrim4 月 04 16:49:49 casey-Virtual-Machine systemd[1]: Started Discard unused blocks once a week.
...

每个 timer 至少有六行信息与之相关:

  • 第一行是 timer 的文件名和对其用途的简短描述。
  • 第二行显示 timer 的状态,它是否被加载,timer unit 文件的完整路径,以及供应商的预设。
  • 第三行显示其活动状态,包括 timer 开始活动的日期和时间。
  • 第四行包含 timer 下次被触发的日期和时间,以及直到触发发生的大致时间。
  • 第五行显示由 timer 触发的事件或服务的名称。
  • 一些(但不是全部)systemd unit 文件有指向相关文档的指针。如上面的 Docs: man:fstrim
  • 最后一行是 timer 所触发的服务的最新实例的日志条目。

创建 timer

优势之一:统一日志收集到 systemd 日志

为了更快了解 timer, 我们创建自己的 service unit 和 timer unit 来触发。

具体用途为:每周定期更新 tailscale 的版本。

首先,创建 tailscale update 服务,如下:

[Unit]
Description=Tailscale update
Wants=tailscale-weekly-update.timer[Service]
Type=oneshot
ExecStart=/usr/bin/tailscale update -yes[Install]
WantedBy=multi-user.target

然后,创建 tailscale update timer, 如下:

[Unit]
Description=Tailscale update
Requires=tailscale-weekly-update.service[Timer]
Unit=tailscale-weekly-update.service
OnCalendar=weekly[Install]
WantedBy=timers.target

最后,启用 timer:

systemctl enable tailscale-weekly-update.timer 

这样就可以了,但是为了演示,执行:systemctl start tailscale-weekly-update.service 手动运行一次。

输出会直接集成到 systemd 日志里,并可以通过 journalctl 查看:(包含手动执行日志,和后续自动定期执行的日志)

$ sudo journalctl -S "2023-03-29 00:00:00" -u tailscale-weekly-update.service
4 月 02 09:14:28 casey-Virtual-Machine systemd[1]: Starting Tailscale node agent...
4 月 02 09:14:30 casey-Virtual-Machine tailscale[6898]: 获取:1 https://pkgs.tailscale.com/stable/ubuntu jammy InRelease
4 月 02 09:14:30 casey-Virtual-Machine tailscale[6898]: 获取:2 https://pkgs.tailscale.com/stable/ubuntu jammy/main amd64 Packages [7,853 B]
4 月 02 09:14:32 casey-Virtual-Machine tailscale[6898]: 已下载 13.9 kB,耗时 1 秒 (14.4 kB/s)
4 月 02 09:14:32 casey-Virtual-Machine tailscale[6898]: 正在读取软件包列表。..
4 月 02 09:14:33 casey-Virtual-Machine tailscale[7101]: 正在读取软件包列表。..
4 月 02 09:14:33 casey-Virtual-Machine tailscale[7101]: 正在分析软件包的依赖关系树。..
4 月 02 09:14:33 casey-Virtual-Machine tailscale[7101]: 正在读取状态信息。..
4 月 02 09:14:33 casey-Virtual-Machine tailscale[7101]: 下列软件包将被升级:
4 月 02 09:14:33 casey-Virtual-Machine tailscale[7101]:   tailscale
4 月 02 09:14:34 casey-Virtual-Machine tailscale[7101]: 升级了 1 个软件包,新安装了 0 个软件包,要卸载 0 个软件包,有 4 个软件包未被升级。
4 月 02 09:14:34 casey-Virtual-Machine tailscale[7101]: 需要下载 23.0 MB 的归档。
4 月 02 09:14:34 casey-Virtual-Machine tailscale[7101]: 解压缩后将会空出 1,024 B 的空间。
4 月 02 09:14:34 casey-Virtual-Machine tailscale[7101]: 获取:1 https://pkgs.tailscale.com/stable/ubuntu jammy/main amd64 tailscale amd64 1.38.3 [23.0 MB]
4 月 02 09:15:13 casey-Virtual-Machine tailscale[7115]: debconf: 无法初始化前端界面:Dialog
4 月 02 09:15:13 casey-Virtual-Machine tailscale[7115]: debconf: (系统未设定 TERM 环境变量,所以对话框界面将不可使用。)
4 月 02 09:15:13 casey-Virtual-Machine tailscale[7115]: debconf: 返回前端界面:Readline
4 月 02 09:15:13 casey-Virtual-Machine tailscale[7115]: debconf: 无法初始化前端界面:Readline
4 月 02 09:15:13 casey-Virtual-Machine tailscale[7115]: debconf: (这个界面要求可控制的 tty。)
4 月 02 09:15:13 casey-Virtual-Machine tailscale[7115]: debconf: 返回前端界面:Teletype
4 月 02 09:15:13 casey-Virtual-Machine tailscale[7115]: dpkg-preconfigure: 重新开启标准输入失败:
4 月 02 09:15:13 casey-Virtual-Machine tailscale[7101]: 已下载 23.0 MB,耗时 40 秒 (577 kB/s)
4 月 02 09:15:14 casey-Virtual-Machine tailscale[7101]: [729B blob data]
4 月 02 09:15:14 casey-Virtual-Machine tailscale[7101]: 准备解压 .../tailscale_1.38.3_amd64.deb  ...
4 月 02 09:15:14 casey-Virtual-Machine tailscale[7101]: 正在解压 tailscale (1.38.3) 并覆盖 (1.38.2) ...
4 月 02 09:15:15 casey-Virtual-Machine tailscale[7101]: 正在设置 tailscale (1.38.3) ...
4 月 02 09:15:23 casey-Virtual-Machine tailscale[7325]: Running kernel seems to be up-to-date.
4 月 02 09:15:23 casey-Virtual-Machine tailscale[7325]: Services to be restarted:
4 月 02 09:15:23 casey-Virtual-Machine tailscale[7325]:  systemctl restart tailscale-weekly-update.service
4 月 02 09:15:23 casey-Virtual-Machine tailscale[7325]: No containers need to be restarted.
4 月 02 09:15:23 casey-Virtual-Machine tailscale[7325]: No user sessions are running outdated binaries.
4 月 02 09:15:23 casey-Virtual-Machine tailscale[7325]: No VM guests are running outdated hypervisor (qemu) binaries on this host.
4 月 02 09:15:24 casey-Virtual-Machine systemd[1]: tailscale-weekly-update.service: Deactivated successfully.
4 月 02 09:15:24 casey-Virtual-Machine systemd[1]: Finished Tailscale node agent.
4 月 02 09:15:24 casey-Virtual-Machine systemd[1]: tailscale-weekly-update.service: Consumed 6.317s CPU time.$ sudo journalctl -S "2023-03-29 00:00:00" -u tailscale-weekly-update.timer
4 月 02 09:14:28 casey-Virtual-Machine systemd[1]: Started Tailscale node agent.
4 月 02 20:01:52 casey-Virtual-Machine systemd[1]: tailscale-weekly-update.timer: Deactivated successfully.
4 月 02 20:01:52 casey-Virtual-Machine systemd[1]: Stopped Tailscale node agent.

如上面的日志,可以很方便地检查 timer 和服务的状态。

在日志这方面,你不需要做任何特别的事情,就可以使tailscale-weekly-update.service unit 中的ExecStart触发器的STDOUT存储在日志中。这都是使用 systemd 运行服务的一部分。

Systemd timer 时间精度

优势之一:针对时间精确度更详细的配置项

从上面日志,如果细看,timer 不会在:00秒的时候准确触发,甚至不会在上一个实例的一分钟内准确触发。这是故意的,但如果有必要的话,可以覆盖它的默认配置。

这种行为的原因是为了防止多个服务在完全相同的时间被触发。例如,你可以使用时间规格,如每周、每天,等等。这些快捷方式都被定义为在它们被触发的那一天的 00:00:00 时触发。当多个 timer 被这样指定时,它们很有可能会试图同时启动。

systemd timer 被有意设计成在指定时间内随机触发,以防止同时触发。它们在一个时间窗口内半随机地触发。根据systemd.timer手册,这个触发时间相对于所有其他定义的 timer 单位来说,保持在一个稳定的位置。

大多数时候,这种概率性的触发时间是没有问题的。当安排备份等任务运行时,只要它们在非工作时间运行,就不会有问题。一个系统管理员可以选择一个确定的开始时间,如典型的 cronjob 规范中的 01:05:00,以不与其他任务冲突,但有很大范围的时间值可以达到这个目的。启动时间中的一分钟随机性通常是不相关的。

然而,对于某些任务,精确的触发时间是一个绝对要求。对于这些任务,你可以通过在 timer unit 文件的 Timer 部分添加这样的配置来指定更高的触发时间跨度精度(如精度在一微秒内):

AccuracySec=1us

时间跨度可用于指定所需的精度,以及为重复性或一次性事件定义时间跨度。它可以识别以下单位:

  • usec, us, µs
  • msec, ms
  • seconds, second, sec, s
  • minutes, minute, min, m
  • hours, hour, hr, h
  • days, day, d
  • weeks, week, w
  • months, month, M (定义为 30.44 天)
  • years, year, y (定义为 365.25 天)

/usr/lib/systemd/system中的所有默认 timer 都指定了一个更大的精度范围,因为精确的时间并不关键。看看系统创建的 timer 中的一些规格:

$ grep Accur /usr/lib/systemd/system/*timer
/usr/lib/systemd/system/fstrim.timer:AccuracySec=1h
/usr/lib/systemd/system/logrotate.timer:AccuracySec=1h
/usr/lib/systemd/system/plocate-updatedb.timer:AccuracySec=20min
/usr/lib/systemd/system/snapd.snap-repair.timer:AccuracySec=10min

Timer 类型

优势之一:除了定时场景,还支持基于 event 的触发

systemd timer 具有 cron 所不具备的其他功能,cron 只在特定的、重复的、实时的日期和时间触发。但是,一个 timer 可以被配置为在系统启动后,或在启动后,或在某个定义的服务 unit 激活后的特定时间内触发。这些被称为单调性 timer。单调指的是一个持续增加的计数或序列。这些 timer 不是持久的,因为它们在每次启动后都会重置。

表 1 列出了单调的 timer 以及每个 timer 的简短定义,还有 "OnCalendar" timer,它不是单调的,用于指定未来的时间,可能是重复的,也可能不是。

Timer单调性定义
OnActiveSec=X这定义了一个相对于 timer 被激活的时刻的 timer。
OnBootSec=X这定义了一个相对于机器启动时间的 timer。
OnStartupSec=X这定义了一个相对于服务管理器首次启动时间的计时器。对于系统 timer unit,这与OnBootSec=非常相似,因为系统服务管理器通常在启动时很早就启动。当配置在每个用户服务管理器中运行的单元时,它主要是有用的,因为用户服务管理器一般只在第一次登录时启动,而不是在启动时。
OnUnitActiveSec=X这定义了一个相对于要激活的 timer 最后一次被激活的时间。
OnUnitInactiveSec=X这定义了一个相对于要激活的 timer 最后被停用的时间的定时器。
OnCalendar=这就用日历事件表达式定义了实时 timer。更多关于日历事件表达式的语法信息请参见systemd.time(7)。否则,其语义与OnActiveSec=及相关设置类似。这个 timer 是最像那些与 cron 服务一起使用的 timer。

表 1: systemd timer 定义

单调 timer 的时间跨度可以使用与前面提到的AccuracySec语句相同的快捷名称,但 systemd 将这些名称规范化为秒。例如,你可能想指定一个 timer,在系统启动 5 天后触发一次事件,可以这样写: OnBootSec=5d。如果主机在2020-06-15 09:45:27启动,timer 将在2020-06-20 09:45:27或之后一分钟内触发。

Calendar event 定义

优势之一:相比 cronjob 更灵活的语法

Calendar event 定义是在所需的重复时间触发 timer 的关键部分。首先看一下OnCalendar设置中使用的一些规格。

systemd 及其 timer 使用的时间和日期规格与 crontab 中使用的格式不同。它比 crontab 更灵活,允许以at命令的方式模糊日期和时间。

使用OnCalendar=的 systemdtimer 的基本格式是DOW YYYY-MM-DD HH:MM:SS。DOW(星期)是可选的,其他字段可以使用星号(*)来匹配该位置的任何值。所有日历时间形式都被转换为规范化的形式。如果没有指定时间,则假定其为 00:00:00。如果没有指定日期但指定了时间,那么下一个匹配可能是今天或明天,这取决于当前的时间。名称或数字可用于月份和星期。可以指定每个单位的逗号分隔的列表。单位范围可以在开始和结束值之间用...来指定。

有几个有趣的选项用于指定日期。波浪号(~)可以用来指定该月的最后一天或该月最后一天之前的指定天数。"/"可以用来指定一周中的某一天作为修饰语。

下面是一些在OnCalendar语句中使用的典型时间规格的例子:

Calendar event 定义描述
DOW YYYY-MM-DD HH:MM:SS
*-*-* 00:15:30每年的每个月的每一天,在午夜后的 15 分钟 30 秒。
Weekly每个星期一的 00:00:00
Mon *-*-* 00:00:00与每周相同
Mon与每周相同
Wed 2020-*-*2020 年的每个星期三,00:00:00
Mon..Fri 2021-*-*2021 年的每个工作日的 00:00:00
2023-6,7,8-1,15 01:15:002023 年 6 月、7 月和 8 月的 1 日和 15 日凌晨 01:15:00
Mon *-05~03任何一年的 5 月的下一个星期一,也是月末的第三天。
Mon..Fri *-08~04任何年份的 8 月底前的第 4 天,如果该天也是工作日,则为 8 月底。
*-05~03/2从五月底开始的第三天,两天后再来一次。每年都会重复。请注意,这个表达式使用了(~)。
*-05-03/2五月的第三天,然后在五月的其余时间里每隔一天。每年重复一次。注意,这个表达式使用了破折号(-)。

表 2: 示例OnCalendar event 定义

测试 calendar 定义

优势之一:更丰富的使用/运维命令集

systemd 提供了一个很好的工具来验证和检查 timer 中的日历时间事件规范。systemd-analyze calendar工具解析了一个日历时间事件规范,并提供了规范化的形式以及其他有趣的信息,比如下一个 "elapse"(即匹配)的日期和时间,以及达到触发时间前的大致时间。

首先,看一下未来的一个没有时间的日期:

$ systemd-analyze calendar 2030-06-17Original form: 2030-06-17
Normalized form: 2030-06-17 00:00:00Next elapse: Mon 2030-06-17 00:00:00 CST(in UTC): Sun 2030-06-16 16:00:00 UTCFrom now: 7 years 2 months left

现在添加一个时间。在这个例子中,日期和时间作为非相关实体被单独分析:

$ systemd-analyze calendar 2030-06-17 15:21:16Original form: 2030-06-17
Normalized form: 2030-06-17 00:00:00Next elapse: Mon 2030-06-17 00:00:00 CST(in UTC): Sun 2030-06-16 16:00:00 UTCFrom now: 7 years 2 months leftOriginal form: 15:21:16
Normalized form: *-*-* 15:21:16Next elapse: Wed 2023-04-05 15:21:16 CST(in UTC): Wed 2023-04-05 07:21:16 UTCFrom now: 21h left

要把日期和时间作为一个 unit 来分析,需要用引号把它们括起来。

$ systemd-analyze calendar "2030-06-17 15:21:16"
Normalized form: 2030-06-17 15:21:16Next elapse: Mon 2030-06-17 15:21:16 CST(in UTC): Mon 2030-06-17 07:21:16 UTCFrom now: 7 years 2 months left

现在测试表 2 中的条目。选一个复杂的:

$ systemd-analyze calendar "2023-6,7,8-1,15 01:15:00"Original form: 2023-6,7,8-1,15 01:15:00
Normalized form: 2023-06,07,08-01,15 01:15:00Next elapse: Thu 2023-06-01 01:15:00 CST(in UTC): Wed 2023-05-31 17:15:00 UTCFrom now: 1 month 26 days left

让我们看一个例子,在这个例子中,我们列出了时间戳表达式的下五个执行时间:

$ systemd-analyze calendar --iterations=5 "Mon *-05~3"Original form: Mon *-05~3
Normalized form: Mon *-05~03 00:00:00Next elapse: Mon 2023-05-29 00:00:00 CST(in UTC): Sun 2023-05-28 16:00:00 UTCFrom now: 1 month 23 days leftIter. #2: Mon 2028-05-29 00:00:00 CST(in UTC): Sun 2028-05-28 16:00:00 UTCFrom now: 5 years 1 month leftIter. #3: Mon 2034-05-29 00:00:00 CST(in UTC): Sun 2034-05-28 16:00:00 UTCFrom now: 11 years 1 month leftIter. #4: Mon 2045-05-29 00:00:00 CST(in UTC): Sun 2045-05-28 16:00:00 UTCFrom now: 22 years 1 month leftIter. #5: Mon 2051-05-29 00:00:00 CST(in UTC): Sun 2051-05-28 16:00:00 UTCFrom now: 28 years 1 month left

这应该给你足够的信息来开始测试你的OnCalendar时间规格。

总结

systemd timer 可以用来执行与 cron 工具相同类型的任务,但在触发事件的 calendar 和单调的时间规格方面提供了更多的灵活性。

除此之外,systemd timer 还有的优势包括:

  • 统一日志收集到 systemd 日志
  • 针对时间精确度更详细的配置项
  • 更丰富的使用/运维命令集

快去尝试迁移你的 cronjob 到 systemd timer 吧~😛😛😛

参考资料

  • Use systemd timers instead of cronjobs
  • Fedora 的 systemd 指南
  • Fedora 的 systemd cheat sheet

三人行, 必有我师; 知识共享, 天下为公. 本文由东风微鸣技术博客 EWhisper.cn 编写.

相关文章:

为什么我推荐你使用 systemd timer 替代 cronjob?

概述 前几天在使用 Terraform cloud-init 批量初始化我的实验室 Linux 机器。正好发现有一些定时场景需要使用到 cronjob, 进一步了解到 systemd timer 完全可以替换 cronjob, 并且 systemd timer 有一些非常有趣的功能。 回归话题:为什么我推荐你使用 systemd t…...

elasticsearch基础6——head插件安装和web页面查询操作使用、ik分词器

文章目录一、基本了解1.1 插件分类1.2 插件管理命令二、分析插件2.1 es中的分析插件2.1.1 官方核心分析插件2.1.2 社区提供分析插件2.2 API扩展插件三、Head 插件3.1 安装3.2 web页面使用3.2.1 概览页3.2.1.1 unassigned问题解决3.2.2 索引页3.2.3 数据浏览页3.2.4 基本查询页3…...

【Linux】七、进程间通信(二)

目录 三、system V(IPC) 3.1 system V共享内存 3.1.1 共享内存的概念 3.1.2 共享内存的原理 3.1.3 创建共享内存(shmget ) 3.1.4 ftok函数 3.1.5 查看共享内存资源 3.1.6 创建共享内存测试代码 3.1.7 再次理解共享内存 3.1.8 释放共享内存(shm…...

Synchronized学习大总结

目录 1.synchronized特性 2.synchronized如何使用 3.synchronized的锁机制 1.synchronized特性 synchronized 是乐观锁,也是悲观锁,是轻量级锁(j基于自旋锁实现),也是重量级锁(基于挂起等待锁实现),它不是读写锁,是互斥锁,当一个线程抢到锁之后,其它线程阻塞等待,进入synchr…...

VN5620以太网测试——环境搭建篇

文章目录 前言一、新建以太网工程二、Port Configuration三、Link up四 Trace界面五、添加Ethernet Packet Builder六、添加ARP Packet七、添加Ethernet IG总结前言 CANoe(CAN open environment)VN5620 :是一个紧凑而强大的接口,用于以太网网络的分析、仿真、测试和验证。 …...

redis哨兵和集群部署手册

一、哨兵模式原理及作用 1.原理 哨兵(sentinel): 是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现 故障时,通过投票机制选择新的master并将所有slave连接到新的master。所以整个运行哨兵的集…...

ctfshow web入门 java 295 298-300

其他没啥好讲的,都是工具就通杀了 web295 漏洞地址 http://ip/S2-048/integration/saveGangster.action 这里我们可以看到他是解析了 尝试使用网上的payload %{(#dmognl.OgnlContextDEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess#dm):((#container#cont…...

SWIG包装器使用指南——(四)C#使用SWIG简介与实践

SWIG系列:http://t.csdn.cn/cIAcr 文章目录一、简介二、全局函数、变量、常量三、继承四、传递指针、引用、数组与值五、基本类型的指针与引用六、基本类型的数组七、基本类型的默认map规则八、常用的typemap方法九、代码插入十、实践10.1 如何映射Foo*&到ref F…...

HashTable, HashMap 和 ConcurrentHashMap

HashTable, HashMap 和 ConcurrentHashMap 都是 Java 集合框架中的类,用于存储和操作键值对。它们之间存在一些关键区别,如下所示: 1.同步性: HashTable:线程安全,所有的方法都是同步的(synchr…...

ToBeWritten之IoT 技战法

也许每个人出生的时候都以为这世界都是为他一个人而存在的,当他发现自己错的时候,他便开始长大 少走了弯路,也就错过了风景,无论如何,感谢经历 转移发布平台通知:将不再在CSDN博客发布新文章,敬…...

基于ASP.NET开发的医院手术麻醉信息管理系统源码 项目源码

系统主要功能介绍: 门诊科室管理系统:手术快速申请、手术申请、手术审核 麻醉科管理系统:手术安排、术后处方、术后小结、PCS实施及管理记录、手术流程 手术护理系统:手术安排、安排临时手术、添加急诊手术、局麻手术护理、整体护…...

伪加密超具体破解办法,直击原理底层,细致演示!!!

前言: 由于我自己目前在misc和取证工作中,也遇到很多压缩包的问题,我个人非常喜欢做压缩包的题目,但也会遇到伪加密问题难以破解,全网ctf教程我都看完了,但是都觉得不够具体,所以我写一篇博客&…...

ChatGPT大规模封锁亚洲地区账号

我是卢松松,点点上面的头像,欢迎关注我哦! 在毫无征兆的情况下,从3月31日开始OpenAI大规模封号,而且主要集中在亚洲地区,特别是ip地址在台湾、日本、香港三地的,命中率目测40%。新注册的账号、…...

脂肪酸脂质Myristic acid PEG NHS,Myristic-acid PEG NHS ester,肉豆蔻酸PEG活性酯,具有优异疏水性

一、基础产品数据: 中文名:肉豆蔻酸PEG N-羟基琥珀酰亚胺,肉豆蔻酸PEG活性酯 英文名:Myristic acid PEG NHS,Myristic-acid PEG NHS ester,Myristic acid PEG SE 结构式(Structural)…...

MFC - CFormView类学习1

CFormView简介 MFC提供了一个名为CFormView的特殊视图类,我们称其为表单视图。表单视图是指用控件来输入和输出数据的视图,用户可以方便地在表单视图中使用控件。表单视图具有对话框和滚动视图的特性,它使程序看起来象是一个具有滚动条的对话…...

图像预处理方法

图像预处理 膨胀腐蚀概述 ⚫ 膨胀、腐蚀属于形态学的操作, 简单来说就是基于形状的一系列图像处理操作 ⚫ 膨胀腐蚀是基于高亮部分(白色)操作的, 膨胀是対高亮部分进行膨胀, 类似“领域扩张”, 腐蚀是高亮部分被腐蚀, 类似“领域被蚕食” ⚫ 膨胀腐蚀的应用和功能: 消除噪声…...

【蓝桥杯C/C++】专题六:动态规划

专题六:动态规划 目录专题六:动态规划导读什么是动态规划解决的问题解题步骤动态规划应该如何debug记忆化搜索斐波那契数题目代码题解爬楼梯题目代码题解使用最小花费爬楼梯题目代码题解不同路径题目题解dfsdp凑硬币题目题解dfsdp滑雪题目代码题解汉罗塔…...

图的定义和基本术语

图的定义和基本术语1.图的定义2.图的基本术语3.图的分类1.图的定义 图是由顶点和有穷非空集合和顶点边的集合吗,表示为G(V,E)。 G表示一个图,V是图G的顶点(数据元素)的集合,E是图G中顶点之间边的集合。在图中&#xf…...

041:cesium加载Blue Marble地图

第041个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中加载Blue Marble地图。Blue Marble是一个术语,用来描述星球漂浮在浩瀚太空中的形象。早在 1972 年,阿波罗 17 号任务的工作人员就首次捕捉到了地球的标志性卫星图像,并将其称为“Blue Marble”。从那时起,NA…...

【概念梳理】激活函数

一、引言 常用的激活函数如下: 1、Sigmoid函数 2、Tanh函数 3、ReLU函数 4、ELU函数 5、PReLU函数 6、Leaky ReLU函数 7、Maxout函数 8、Mish函数 二、激活函数的定义 多层神经网络中,上层节点的输出和下层节点的输入之间具有一个函数关系,…...

【python】@property 和 @staticmethod

property 和 staticmethod 是 Python 中的两个装饰器,它们分别用于在类中创建属性或静态方法。它们的作用如下: property property:用于将类的一个方法作为属性访问。在 Python 中,使用“getter” 和“setter”方法来实现属性&a…...

Spring题集 - Spring AOP相关面试题总结

文章目录01. Spring AOP 的理解?02. Spring AOP 思想的代码实现03. Spring AOP 的相关术语有哪些?04. Spring AOP 基于注解的切面实现?05. Spring AOP 的通知有哪些类型?06. AOP 有哪些实现方式?07. Spring AOP 和 AspectJ AOP 有…...

分考场

[蓝桥杯 2017 国 C] 分考场(假题&#xff1a;最小色数) 题目描述 nnn 个人参加某项特殊考试。 为了公平&#xff0c;要求任何两个认识的人不能分在同一个考场。 求最少需要分几个考场才能满足条件。 输入格式 第一行&#xff0c;一个整数 n(1<n<100)n(1<n<100…...

BI技巧丨DAX Studio

DAX Studio DAX Studio&#xff0c;作为PowerBI外部插件使用率排名第一的插件&#xff0c;相信各位小伙伴或多或少都听说过&#xff0c;那么DAX Studio具体有哪些功能呢&#xff1f; PS&#xff1a;DAX Studio的下载链接&#xff0c;小伙伴们可以自行搜索&#xff0c;这里就不…...

Java 8常用时间 API

Date: 你不爱我了吗? &#x1f6a1;本地时间时区相关格式化在Java 8中&#xff0c;Instant类用于表示时间戳&#xff0c;相当于旧的Date类&#xff1b;LocalDateTime类用于表示日期和时间&#xff0c;相当于旧的Calendar类&#xff1b;DateTimeFormatter类用于格式化日期和时间…...

C++运算符

C运算符 运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C 内置了丰富的运算符&#xff0c;并提供了以下类型的运算符&#xff1a; 算术运算符关系运算符逻辑运算符位运算符赋值运算符杂项运算符 1. 算术运算符 运算符描述实例把两个操作数相加A B 将得到 30-从第…...

低/无代码赋能企业,IT与业务的角色正在悄然改变

现在这个社会&#xff0c;年轻人的压力是真的大&#xff0c;需要会的技能多到数不清。想学习多点技能也不知道去哪学&#xff0c;主要是网络资源太丰富&#xff0c;很难找到一个适合自己的。那接下来推荐4个大神级别的资源网站你可一定得码住&#xff0c;都是年轻人特别 …...

SpringCloud学习2(Spring Cloud Netflix)负载均衡Ribbon、Feign负载均衡、Hystix服务熔断

文章目录负载均衡RibbonRibbon的作用代码实现生产者cloud1_provider实现配置文件在HiController中编写以下代码启动集群消费者cloud1_consumer实现引入依赖编写配置文件编写启动类&#xff0c;并给RestTemplate配置LoadBalanced注解编写RestController来测试Feign负载均衡简介F…...

Spring 源码解析 - @Async 注解下的循环依赖问题原理

一、Async 注解下的循环依赖问题 我们都知道 Spring IOC 单例模式下可以帮助我们解决循环依赖问题&#xff0c;比如下面自己依赖自己循环依赖的场景&#xff1a; Component public class TestAsync {ResourceTestAsync async;public void test() {System.out.println("t…...

8个全球性编程比赛,天才程序员的梦想舞台

很多编程爱好者在学习之初&#xff0c;都渴望与全球的程序员一较高下&#xff0c;以证明自己的实力。 一些全球性的编程竞赛为他们提供了这样的机会&#xff0c;不仅可以与全世界的顶尖程序员们交流&#xff0c;还有机会获得丰厚的奖金和进入顶级公司的机会&#xff0c;更重要…...