Ansible Playbook原理与实践(Principles and Practice of Ansible Playbook)
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
本人主要分享计算机核心技术:系统维护、数据库、网络安全、自动化运维、容器技术、云计算、人工智能、运维开发、算法结构、物联网、JAVA 、Python、PHP、C、C++等。
不同类型针对性训练,提升逻辑思维,剑指大厂,非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。
云平台管理之Ansible Playbook 原理与实践
Ansible Playbook 简介
Ansible Playbook 是 Ansible 的核心组件之一,它允许用户以 YAML 格式编写配置文件,用于描述希望远程系统执行的一系列任务。Playbook 提供了一种方式来编排和执行这些任务,确保配置的一致性,或者简单地执行一些常见的任务。Playbook 的使用使得 Ansible 成为一个强大的配置管理工具,尤其适用于需要跨多个系统执行多个操作的情况。
Playbook 的基本原理包括:
- 配置管理:通过 Playbook,可以定义和执行一系列任务,以管理和配置远程系统的状态。
- 编排任务:Playbook 可以对任务进行排序和编排,确保按照正确的顺序执行任务。
- 并行处理:通过异步执行和适当的配置,Playbook 可以实现并行处理多个任务,提高工作效率。
- 权限管理:通过使用 become 功能,Playbook 可以以不同的用户权限执行任务,满足不同的系统需求。
实践方面,使用 Playbook 可以大大简化复杂的应用部署和配置管理过程。通过编写 Playbook,可以清晰地定义部署流程、配置变更、系统状态检查等任务,并通过 Ansible 引擎执行这些任务。Playbook 的使用不仅提高了工作效率,还减少了人为错误的可能性,使得 IT 基础设施的管理更加可靠和高效。
Playbooks是Ansible的配置,部署和编排语言。playbook是由一个或多个play组成的列表,play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来讲,所谓的task无非是调用ansible的一个module。将多个play组织在一个playbook中,即可以让它们联合起来按事先编排的机制完成某一任务。
Ansible Palybook的编写是基于YAML语言的。YAML语言,即Yet Another Markup Language,是一种能被计算机直接识别的标记语言,同时也方便人的阅读,且方便和脚本语言交互。但是,YAML的配置即为严格,在配置时必须注重空格的数量。总的来看,YAML语言特性如下:
- 1、可读性强
- 2、和脚本语言的交互性好
- 3、使用实现语言的数据类型
- 4、一致的信息模型
- 5、易于实现
- 6、可以基于流来处理
- 7、可扩展性强
Ansible Playbook 组件
Ansible的Playbook有以下组件:
- Target
- 定义playbook的远程主机组,即控制的下游设备信息
- Variable
- 定义Playbook所使用的变量。
- Task
- 定义Playbook控制下游设备要执行的命令。
- Handler
- 定义在Palybook在Task执行完毕后要调用的任务。
Ansible Playbook各组件参数
Ansible的上述组件的参数如下:
Target常用参数
代码语言:javascript
hosts #定义Ansible用户控制的下游设备
remote_user #定义执行Ansible设置的用户
sudo #设置为yes时,执行任务时使用root权限
sudo_user #指定sudo的普通用户
connection #默认基于ssh链接客户端
gather_facts #获取远程主机facts基础信息
Variable常用参数
vars #定义变量
vars_files #指定变量文件
vars_prompt #用户交互模式自定义变量
setup #通过远程gather_facts获取的信息
Task常用参数
name #任务的名称,在Ansible运行的过程中起到提示的作用,会打印在屏幕上
action #Ansible控制下游设备的命令,通过Ansible的各个模块来进行控制
template #Ansible控制下游设备的模板
handler #定义一个调用,该调用在Handler处被定义,在所有的Task结束后被执行。
Playbook基本语法
playbook使用yaml语法格式,后缀可以是yaml,也可以是yml。
[root@localhost ~]$ vim test.yaml
--- #表示文档开始
- hosts: test # "- "表示一个块序列的节点,注意:横杠后面有空格,可以写主机名,主机组名,多个使用逗号隔开remote_user: root #指定在进行远程操作时使用root用户进行操作tasks: #使用tasks关键字指明要进行操作的任务列表,之后的行都属于tasks键值对中的值。- name: Ping #每个任务都以"- "开头,每个任务都有自己的名字,任务名使用name关键字进行指定ping: #ansible模块- name: make directory test #第二个任务使用file模块,使用file模块时,指定了path参数与state参数的值。file: #ansible模块path: /data/test #模块的参数state: directory --- #标记文件的开始
- hosts: webservers #指定该playbook在哪个服务器上执行vars: #表示下面是定义的变量,http_port: 80 #变量的形式,key: value,这里http_port是变量名,80是值max_clients: 200remote_user: root #指定远程的用户名,这里缩进和vars保持了一致,说明变量的代码块已经结束。tasks: #下面构成playbook的tasks,每个task都有 - name: 开始,name指定该任务的名称。- name: ensure apache is at the latest version #指定该任务的名称。yum: pkg=httpd state=latest #yum说明要是用的模板名称,后面指定对应的参数,这两行结合起来就相当于一个shell命令。- name: write the apache config file #每个task之间可以使用空行来做区分。template: src=/srv/httpd.j2 dest=/etc/httpd.conf#需要说明的是缩进的意义和python中缩进的意义是一样,是来区分代码块的。
检测语法
[root@localhost ~]$ ansible-playbook --syntax-check /path/to/playbook.yaml
测试运行
[root@localhost ~]$ ansible-playbook -C /path/to/playbook.yaml
运行
[root@localhost ~]$ ansible-playbook /path/to/playbook.yaml
示例:Playbook 创建用户
[root@localhost ~]$ vim sysuser.yml
---
- hosts: allremote_user: roottasks:- name: create mysql useruser: name=mysql system=yes uid=36- name: create a groupgroup: name=httpd system=yes
Playbook示例 安装nginx服务
[root@localhost ~]$ vim nginx.yml
- hosts: allremote_user: roottasks:- name: add group nginxuser: name=nginx state=present- name: add user nginxuser: name=nginx state=present group=nginx- name: Install Nginxyum: name=nginx state=present- name: Start Nginxservice: name=nginx state=started enabled=yes
tags: 添加标签
可以指定某一个任务添加一个标签,添加标签以后,想执行某个动作可以做出挑选来执行,多个动作可以使用同一个标签。
示例:httpd.yml
代码语言:javascript复制
- hosts: websrvsremote_user: roottasks:- name: Install httpdyum: name=httpd state=presenttage: install - name: Install configure filecopy: src=files/httpd.conf dest=/etc/httpd/conf/tags: conf- name: start httpd servicetags: serviceservice: name=httpd state=started enabled=yesansible-playbook -t install,conf httpd.yml 指定执行install,conf 两个标签
handlers
handlers和notify结合使用触发条件
Handlers 实际上就是一个触发器是task列表,这些task与前述的task并没有本质上的不同,用于当关注的资源发生变化时,才会采取一定的操作。
Notify此action可用于在每个play的最后被触发
这样可避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的操作
在系统中,我们修改了服务器的配置文件,这时候就需要重启操作服务,就可以使用到handlers。配合 notify使用。
代码语言:javascript
---
- hosts: control-noderemote_user: rootvars:- pkg: httpd- name: template configuration filetemplate: src=template.j2 dest=/etc/foo.conf #修改了配置文件然后依次启动memcached和apache服务。notify: #使用notify来声明引用handlers。- restart memcached- restart apachehandlers: #下面定义了两个handlers- name: restart memcachedservice: name=memcached state=restarted- name: restart apacheservice: name=apache state=restarted
在使用handlers的过程中,有以下几点需要注意:
- handlers只有在其所在的任务被执行时,都会被运行;
- handlers只会在Play的末尾运行一次;如果想在一个Playbook的中间运行handlers,则需要使用meta模块来实现,例如:- meta: flush_handlers。
- 如果一个Play在运行到调用handlers的语句之前失败了,那么这个handlers将不会被执行。我们可以使用mega模块的–force-handlers选项来强制执行handlers,即使在handlers所在Play中途运行失败也能执行。
register 和when
register 用于注册一个变量,保存命令的结果(shell或command模块),这个变量可以在后面的task、when语句或模板文件中使用。
代码语言:javascript
- shell: /bin/pwdregister: pwd_result
debug:#msg: "{{ pwd_result }}" # 输出全部信息#msg: "{{ pwd_result.cmd }}" # 引用方式一msg: "{{ pwd_result['stdout_lines'] }}" # 引用方式二
when 相当于shell脚本里的if 判断,when语句就是用来实现这个功能的,它是一个jinja2的语法,但是不需要双大括号,用法很简单。
- name: echo date #执行了一个 date 命令,register 关键字将 date 命令的输出存储到 date_output 变量名command: date register: date_output - name: echo date_output #用 when 对关键字对分析后的进行判断,如果匹配,则执行这个 task,不匹配就不执行command: echo "30"when: date_output.stdout.split(' ')[2] == "30"
这里第 1 个 task 是执行了一个 date 命令,register 关键字将 date 命令的输出存储到 date_output 变量名。第 2 个 task 对输出进行分析,并使用 when 对关键字对分析后的进行判断,如果匹配,则执行这个 task,不匹配就不执行。这里要重点说下的,因为 register 获取到的输出内容都是字符串,而 ansible 又是 python 写的,你可以使用 python 字符串的方法对其做处理,比如本文中使用的 split,还可以使用 find 方法。
示例
tasks:- name: "shutdown RedHat flavored systems"shell: /sbin/shutdown -h nowwhen: ansible_os_family == "RedHat" #当系统属于红帽系列,执行shell模块
循环
标准循环关键字:”with_items” ,对迭代项的引用,固定变量名为"item”,使用with_item属性给定要迭代的元素。
[root@localhost ~]$ cat xh.yml
---
- hosts: allgather_facts: notasks:- name: dispaly listdebug: msg="{{item}}"with_items:- one- two- three- four
[root@localhost ~]$ ansible-playbook -i hosts xh.yml PLAY [all] *************************************************************************************************************
TASK [dispaly xunhuan] *************************************************************************************************
ok: [192.168.52.129] => (item=one) => {"changed": false, "item": "one", "msg": "one"
}
ok: [192.168.52.129] => (item=two) => {"changed": false, "item": "two", "msg": "two"
}
ok: [192.168.52.129] => (item=three) => {"changed": false, "item": "three", "msg": "three"
}
ok: [192.168.52.129] => (item=four) => {"changed": false, "item": "four", "msg": "four"
}
安装一堆软件包。
---- hosts: localhosttasks: - yum: name="{{item}}" state=installedwith_items: - pkg1- pkg2- pkg3
它会一个一个迭代到特殊变量"{{item}}"处。
loop等价于with_list,从名字上可以知道它是遍历数组(列表)的,所以在loop指令中,每个元素都以列表的方式去定义。列表有多少个元素,就循环执行file模块多少次,每轮循环中,都会将本次迭代的列表元素保存在控制变量 item中。
安装多个软件
tasks:- name: "Install Packages"yum: name={{ item }} state=latestloop:- httpd- mysql-server- php
模板templates
Jinja2语言,使用字面量,有下面形式
字符串:使用单引号或双引号
数字:整数,浮点数
列表:[item1, item2, …]
元组:(item1, item2, …)
字典:{key1:value1, key2:value2, …}
布尔型:true/false
算术运算:+, -, *, /, //, %, **
比较操作:==, !=, >, >=, <, <=
逻辑运算:and,or,not
流表达式:For,If,When
template 的使用
templates是ansible的一个模块,其功能是根据模板文件动态生成配置文件,templates文件必须存放于templates目录下,且命名为".j2"结尾,yaml/yml文件需要和templates目录平级,这样我们在yml文件中调用模板的时候,就不需要写模板文件的路径,否则需要描述模板文件的路径,因为template模块会自动去找templates目录下的模板文件.
./
├── temnginx.yml
└── templates
└── nginx.conf.j2
template示例
示例:利用template 同步nginx配置文件,准备templates/nginx.conf.j2文件。
vim temnginx.yml
- hosts: websrvsremote_user: roottasks:- name: template config to remote hoststemplate: src=nginx.conf.j2 dest=/etc/nginx/nginx.confansible-playbook temnginx.yml
for循环使用
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen }}
}
{% endfor %}
if单分支选择使用
{% if vhost.server_name is defined %}server_name {{ vhost.server_name }}
{% endif %}
if多分支选择使用
{%if vhost.port is undefined %}http_port=80
{%elif vhost.port == 81%}http_port=81
{%else%}http_port = 83
{%endif%}
单行注释
{#% for i in list %#}
roles
Roles介绍
ansible自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令引入即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷的include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。主要使用场景代码复用度较高的情况下。
Roles目录结构
各目录含义解释
roles: <--所有的角色必须放在roles目录下,这个目录可以自定义位置,默认的位置在/etc/ansible/rolesproject: <---具体的角色项目名称,比如nginx、tomcat、phpfiles: <--用来存放由copy模块或script模块调用的文件。templates: <--用来存放jinjia2模板,template模块会自动在此目录中寻找jinjia2模板文件。tasks: <--此目录应当包含一个main.yml文件,用于定义此角色的任务列表,此文件可以使用include包含其它的位于此目录的task文件。main.ymlhandlers: <--此目录应当包含一个main.yml文件,用于定义此角色中触发条件时执行的动作。main.ymlvars: <--此目录应当包含一个main.yml文件,用于定义此角色用到的变量。main.ymldefaults: <--此目录应当包含一个main.yml文件,用于为当前角色设定默认变量。main.ymlmeta: <--此目录应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系。main.ymlroles/example_role/files/ #所有文件,都将可存放在这里
roles/example_role/templates/ #所有模板都存放在这里
roles/example_role/tasks/main.yml #主函数,包括在其中的所有任务将被执行
roles/example_role/handlers/main.yml #所有包括其中的 handlers 将被执行
roles/example_role/vars/main.yml #所有包括在其中的变量将在roles中生效
roles/example_role/meta/main.yml #roles所有依赖将被正常登入
Roles示例
通过ansible roles安装配置httpd服务,此处的roles使用默认的路径/etc/ansible/roles。
#在ansible目录下面,建立roles目录
#修改配置文件,使系统能够读取roles目录
[root@ansible ~]$ cat /etc/ansible/ansible.cfg | grep roles
# additional paths to search for roles in, colon separated
#roles_path = /etc/ansible/roles #roles默认路径
# by default, variables from roles will be visible in the global variable
创建role的步骤:
- (1) 创建以roles命名的目录。
- (2) 在roles目录中分别创建以各角色名称命名的目录,如webservers等。
- (3) 在每个角色命名的目录中分别创建files、handlers、meta、tasks、templates和vars目录;用不到的目录可以创建为空目录,也可以不创建 。
- (4) 在playbook文件中,调用各角色。
实验: 创建httpd角色
#创建roles目录
mkdir roles/{httpd,mysql,redis}/tasks -pv
mkdir roles/httpd/{handlers,files}
#查看目录结构
tree roles/roles/├── httpd│ ├── files│ ├── handlers│ └── tasks├── mysql│ └── tasks└── redis└── tasks
#创建目标文件
cd roles/httpd/tasks/
touch install.yml config.yml service.yml
#vim install.yml- name: install httpd packageyum: name=httpdvim config.yml- name: config file copy: src=httpd.conf dest=/etc/httpd/conf/ backup=yes vim service.yml- name: start service service: name=httpd state=started enabled=yes#创建main.yml主控文件,调用以上单独的yml文件,main.yml定义了谁先执行谁后执行的顺序vim main.yml- include: install.yml- include: config.yml- include: service.yml#准备httpd.conf文件,放到httpd单独的文件目录下cp /app/ansible/flies/httpd.conf ../files/#创建一个网页vim flies/index.html<h1> welcome to weixiaodong home <\h1>#创建网页的yml文件vim tasks/index.yml- name: index.htmlcopy: src=index.html dest=/var/www/html #将网页的yml文件写进mian.yml文件中vim mian.yml- include: install.yml- include: config.yml- include: index.yml- include: service.yml#在handlers目录下创建handler文件mian.yml
vim handlers/main.yml
- name: restart service httpdservice: name=httpd state=restarted#创建文件调用httpd角色
cd /app/ansidle/roles
vim role_httpd.yml
---
# httpd role
- hosts: appsrvsremote_user: root roles: #调用角色- role: httpd #查看目录结构
tree
.
httpd
├── files
│ ├── httpd.conf
│ └── index.html
├── handlers
│ └── main.yml
└── tasks├── config.yml├── index.yml├── install.yml├── main.yml└── service.ymlansible-playbook role_httpd.yml
创建目录
[root@ansible ~]$ cd /etc/ansible/roles/
# 创建需要用到的目录
[root@ansible roles]$ mkdir -p httpd/{handlers,tasks,templates,vars}
[root@ansible roles]$ cd httpd/
[root@ansible httpd]$ tree .
.
├── handlers
├── tasks
├── templates
└── vars4 directories, 0 file
变量文件准备vars/main.yml
[root@ansible httpd]$ vim vars/main.yml
PORT: 8088 #指定httpd监听的端口
USERNAME: www #指定httpd运行用户
GROUPNAME: www #指定httpd运行组
配置文件模板准备templates/httpd.conf.j2
# copy一个本地的配置文件放在templates/下并已j2为后缀
[root@ansible httpd]$ cp /etc/httpd/conf/httpd.conf templates/httpd.conf.j2# 进行一些修改,调用上面定义的变量
[root@ansible httpd]$ vim templates/httpd.conf.j2
Listen {{ PORT }}
User {{ USERNAME }}
Group {{ GROUPNAME }}
任务剧本编写,创建用户、创建组、安装软件、配置、启动等
# 创建组的task
[root@ansible httpd]$ vim tasks/group.yml
- name: Create a Startup Groupgroup: name=www gid=60 system=yes# 创建用户的task
[root@ansible httpd]$ vim tasks/user.yml
- name: Create Startup Usersuser: name=www uid=60 system=yes shell=/sbin/nologin# 安装软件的task
[root@ansible httpd]$ vim tasks/install.yml
- name: Install Package Httpdyum: name=httpd state=installed# 配置软件的task
[root@ansible httpd]$ vim tasks/config.yml
- name: Copy Httpd Template Filetemplate: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.confnotify: Restart Httpd# 启动软件的task
[root@ansible httpd]$ vim tasks/start.yml
- name: Start Httpd Serviceservice: name=httpd state=started enabled=yes# 编写main.yml,将上面的这些task引入进来
[root@ansible httpd]$ vim tasks/main.yml
- include: group.yml
- include: user.yml
- include: install.yml
- include: config.yml
- include: start.ym
编写重启httpd的handlers,handlers/main.yml
[root@ansible httpd]$ vim handlers/main.yml
# 这里的名字需要和task中的notify保持一致
- name: Restart Httpdservice: name=httpd state=restarted
编写主的httpd_roles.yml文件调用httpd角色
[root@ansible httpd]$ cd ..
[root@ansible roles]$ vim httpd_roles.yml
---
- hosts: allremote_user: rootroles:- role: httpd #指定角色名称
整体的一个目录结构查看
[root@ansible roles]$ tree .
.
├── httpd
│ ├── handlers
│ │ └── main.yml
│ ├── tasks
│ │ ├── config.yml
│ │ ├── group.yml
│ │ ├── install.yml
│ │ ├── main.yml
│ │ ├── start.yml
│ │ └── user.yml
│ ├── templates
│ │ └── httpd.conf.j2
│ └── vars
│ └── main.yml
└── httpd_roles.yml5 directories, 10 files
测试playbook语法是否正确
[root@ansible roles]$ ansible-playbook -C httpd_roles.ym
上面的测试没有问题,正式执行playbook
[root@ansible roles]$ ansible-playbook httpd_roles.ym
Ansible性能调优
相比于其他的自动化配置工具,Ansible的一个突出特性就是它是基于SSH链接对下游设备进行控制的,这样做的突出好处就是方便,下游设备不需要安装客户端软件。但是这也不可避免的带来一个问题,即Ansible的执行速度较慢。并且,随着Ansible控制设备的增多,Ansible的执行速度会越来越慢。
关于Ansible执行速度的问题,尽管是Ansible的硬伤,但是我们还是可以对其进行部分的优化,尽量的加快Ansible的执行速度。对Ansible的优化可以有两个思路,一个是优化SSH链接,使得SSH的传输速度变快。
另一个如下图所示:
每次Ansible Playbook在执行时,都会收集下游设备的信息,这个过程通常要耗费较长的时间。因此,我们可以考虑使用Redis对这些信息进行缓存,从而加快收集信息的速度,如果业务环境允许,我们也可以直接控制Ansible设备跳过该步骤。
Ansible SSH链接调优
SSH关闭密钥检测
在默认情况下,以SSH登录远程设备时,该设备会检查远程主机的公钥,并且将该公钥记录在~/.ssh/known_hosts文件中,当下次该主机访问时,OpenSSH会核对公钥。如果公钥不同,则OpenSSH会发出警告,如果公钥相同,则OpenSSH则会提示输入密码。
SSH对主机公钥的检查是根据StrictHostKeyChecking变量来设定的,StrictHostKeyChecking的检查级别包括:no(不检查),ask(是否检查要询问),yes(每次都检查),False(关闭检查)。
我们可以在Ansible的配置文件中defaults模块下加入如下代码:
host_key_checking = False
加入后,配置文件如下所示:
这样,Ansible就可以关闭密钥检测了。
OpenSSH链接优化
在使用OpenSSH服务时,默认情况下服务器端会根据客户端的IP地址进行DNS反向解析,得到客户端的主机名,然后根据获取到的主机名再次进行DNS查询得到IP地址,比较这两个IP地址是否一样。这样做可以在一定程度上提高安全性,但是却会浪费时间,因此,我们可以通过关闭这一特性,来实现加速SSH链接速度的目的。 关闭该特新需要进入到/etc/ssh/sshd_config目录下,找到UseDNS的参数,将其修改为no,修改后的配置文件如下所示:
之后,重启SSHD服务即可生效。
SSH pipelining链接加速
SSH的pipelining是另一个加速Ansible执行速度的方法。在Ansible的设置中,SSH的pipelining功能时默认关闭的,这是为了兼容不同的sudo配置,主要是requieretty选项。因此,如果我们不需要在Ansible的控制中使用sudo选项,可以关闭这一选项以加快SSH链接速度。
如果要关闭这一项,可以打开Ansible的配置文件/etc/ansible/ansbile.cfg,将pipelining = False改为True即可,修改后的配置文件如下所示:

Ansible Facts调优
关闭Gather Facts
为了减少Ansible在收集客户端信息时的时间,我们首先想到的就是直接删除这一选项。要删除这一步骤,我们可以在palybook文件中添加一行:
gather_facts: no
添加后的Playbook文件如下所示:

这样,我们在执行该Playbook时,就不会再次进行gather_facts的步骤了,结果如下所示:
将Facts信息存入Redis缓存
除了删除这一步之外,我们还可以考虑将客户端信息写入内存,以加快信息查询。
相关文章:
Ansible Playbook原理与实践(Principles and Practice of Ansible Playbook)
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 本人主要分享计算机核心技…...
解决OpenCV保存视频 视频全部为绿色的bug
目录 项目场景: 问题描述 原因分析: 解决方案: 项目场景: 使用OpenCV-Python 保存视频,视频为numpy array格式,保存的视频全部为无意义的绿色。 问题描述 用opencv 保存的视频会出现全部为绿色的情况&…...
手机使用指南:如何在没有备份的情况下从 Android 设备恢复已删除的联系人
在本指南中,您将了解如何从 Android 手机内存中恢复已删除的联系人。Android 诞生、见证并征服了 80% 的智能手机行业。有些人可能将此称为“非常大胆的宣言”,但最近的统计数据完全支持我们的说法。灵活性、高度改进的可用性和快速性是 Android 操作系统…...
TS系列(6):函数
你好,我是沐爸,欢迎点赞、收藏、评论和关注。 TS系列(1):TS是什么?如何使用? TS系列(2):类型声明、类型推断和类型总览 TS系列(3)&…...
网盘能否作为FTP替代产品?企业该如何进行FTP国产化替代?
近年来,信创的概念引入和高效实践落地让更多的行业企业自发性地进行国产化替代,目前信创国产化替代还多发生在操作系统和应用层面,软件工具等目前还在下一阶段规划,但很多企业未雨绸缪,已经在做调研和尝试。 FTP作为世…...
Python操作MongoDB
一、Python链接MongoDB 1、安装pymongo包 使用包管理器安装 pip3 insatll pymongo 2、连接MongoDB 首先需要导入pymongo包: from pymongo import MongoClient 创建MongoClient对象: from pymongo import MongoClient #创建MongoClient对象&#…...
Redis --- 第二讲 --- 特性和安装
一、背景知识 Redis特性: Redis是一个在内存中存储数据的中间件,用于作为数据库,作为缓存,在分布式系统中能够大展拳脚。Redis的一些特性造就了现在的Redis。 在内存中存储数据,通过一系列的数据结构。MySQL主要是通…...
基于单片机的两轮直立平衡车的设计
本设计基于单片机设计的两轮自平衡小车,其中机械部分包括车体、车轮、直流电机、锂电池等部件。控制电路板采用STC12C5A60S2作为主控制器,采用6轴姿态传感器MPU6050测量小车倾角,采用TB6612FNG芯片驱动电机。通过模块化编程完成了平衡车系统软…...
828华为云征文|部署个人知识管理系统 SiyuanNote
828华为云征文|部署个人知识管理系统 SiyuanNote 一、Flexus云服务器X实例介绍二、Flexus云服务器X实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置2.4 Docker 环境搭建 三、Flexus云服务器X实例部署 SiyuanNote3.1 SiyuanNote 介绍3.2 SiyuanNote 部署3.3 Siyua…...
MATLAB中pcg函数用法
目录 语法 说明 示例 线性系统的迭代解 使用指定了预条件子的 pcg 提供初始估计值 使用函数句柄代替数值矩阵 pcg函数的功能是求解线性系统 - 预条件共轭梯度法。 语法 x pcg(A,b) x pcg(A,b,tol) x pcg(A,b,tol,maxit) x pcg(A,b,tol,maxit,M) x pcg(A,b,tol,ma…...
Veritus netbackup 管理控制台无法连接:未知错误
节假日停电,netbackup服务器意外停机后重新开机,使用netbackup管理控制台无法连接,提示未知错误。 ssh连接到服务器,操作系统正常,那应该是应用有问题,先试一下重启服务器看看。重新正常关机,重…...
安全中心 (SOC) 与 网络运营中心 (NOC)
NOC 和 SOC 之间的区别 网络运营中心 (NOC) 负责维护公司计算机系统的技术基础设施,而安全运营中心 (SOC) 则负责保护组织免受网络威胁。 NOC 专注于防止自然灾害、停电和互联网中断等自然原因造成的网络干扰,而 SOC 则从事监控、管理和保护。 NOC 提…...
WPS使用越来越卡顿
UOS统信wps频繁的使用后出现卡顿问题,通过删除或重命名kingsoft文件缓存目录。 文章目录 一、问题描述二、问题原因三、解决方案步骤一步骤二步骤三 一、问题描述 用户在频繁的使用wps处理工作,在使用一段时间后,用户反馈wps打开速度慢&…...
吴恩达深度学习笔记:卷积神经网络(Foundations of Convolutional Neural Networks)2.5-2.6
目录 第四门课 卷积神经网络(Convolutional Neural Networks)第二周 深度卷积网络:实例探究(Deep convolutional models: case studies)2.5 网络中的网络以及 11 卷积(Network in Network and 11 convoluti…...
C# 解决Excel边框样式无法复制问题及实现格式刷功能
目录 问题现象 范例运行环境 解决方案 剪贴板加特殊粘贴 自定义样式 直接赋值 完美方案 小结 问题现象 在运行数据表数据导出到 EXCEL 数据输出时遇到了一个问题,开发者设计了单行细线下边框的输出模板,如下图设计: 其中 <%syst…...
前端组件化开发
假设这个页面是vue开发的,如果一整个页面都是编写在一个vue文件里面,后期不好维护,会特别的庞大,那么如何这个时候需要进行组件化开发。组件化开发后必然会带来一个问题需要进行组件之间的通信。组要是父子组件之间通信࿰…...
异步操作实现线程池
文章目录 futureasyncpromisepackage task C11线程池实现 future 在C11标准库中,提供了一个future的模板类,它表示的是一个异步操作的结果,当在多线程编程中使用异步任务的时候,使用这个类可以帮助在需要的时候获取到对应的数据处…...
长期提供APX515/B原装二手APX525/B音频分析仪
Audio Precision APx515 是一款针对生产测试而优化的高性能音频分析仪。它因其速度、性能、自动化和易用性而成为一流的仪器。它具有卓越的性能,具有 –106 dB 的典型 THDN、1M 点 FFT 和 192k 数字 I/O,以及所有 APx 系列音频分析仪的一键式自动化和易用…...
【数据库差异研究】update与delete使用表别名的研究
目录 ⚛️总结 ☪️1 Update ♋1.1 测试用例UPDATE users as a SET a.age 111 WHERE a.name Alice; ♏1.2 测试用例UPDATE users as a SET a.age 111 WHERE name Alice; ♐1.3 测试用例UPDATE users as a SET age 111 WHERE a.name Alice; ♑1.4 测试用例UPDATE us…...
idea远程连接docker
idea远程连接docker docker、ubuntu、linux、远程连接、IntelliJ idea注意!本文中开启docker远程连接的方法只能在确定环境安全的内网中使用,不可在公网服务器设置,有极大安全风险! 注意!本文中开启docker远程连接的…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
