PostgreSQL技术大讲堂 - 第48讲:PG高可用实现keepalived

PostgreSQL从小白到专家,是从入门逐渐能力提升的一个系列教程,内容包括对PG基础的认知、包括安装使用、包括角色权限、包括维护管理、、等内容,希望对热爱PG、学习PG的同学们有帮助,欢迎持续关注CUUG PG技术大讲堂。

第48讲:PG高可用实现

内容1:keepalived简介

内容2:Keepalived安装与配置

内容3:Keepalived&流复制实现高可用

内容4:主备切换技巧

PostgreSQL技术大讲堂 第48讲:PG高可用实现,

往期视频和文档,联系 ”CUUG“客服

keepalived简介

Keepalived是一个用C编写的路由软件。

keepalive起初专门为lvs负载均衡软件设计的,用来管理监控lvs集群系统中各个服务节点的状态,后来又加入了可以实现高可用的vrrp功能。

该项目的主要目标是为Linux系统和基于Linux的基础架构提供简单而强大的负载平衡和高可用性设施。 负载平衡框架依赖于众所周知且广泛使用的Linux虚拟服务器(IPVS)内核模块,提供Layer4负载均衡。

keepalived完全遵守VRRP协议,包括竞选机制等等,此外,Keepalived为VRRP有限状态机实现了一组挂钩,提供低级和高速协议交互。为了提供最快的网络故障检测,Keepalived实现了BFD协议。VRRP状态转换可以考虑BFD提示来驱动快速状态转换。Keepalived框架可以单独使用,也可以一起使用,以提供灵活的基础架构。

这个协议起先应用于网络,网络在设计的时候必须考虑到冗余容灾,包括线路冗余,设备冗余等,防止网络存在单点故障,那在路由器或三层交换机处实现冗余就显得尤为重要,在网络里面有个协议就是来做这事的,这个协议就是VRRP协议,Keepalived就是巧用VRRP协议来实现高可用性(HA)的。

其用IP组播的方式,实现服务节点间的通信, 通过一种竞选机制来将路由任务交给某台VRRP路由器. 工作时主节点广播发送VRRP协议报文, 备节点接收报文, 若一段时间(默认3个报文发送时间)备节点接收不到主节点发送的报文, 就会启动接管程序接管主节点的资源. 备节点可以有多个, 通过优先级竞选。

Keepalived组件进程

keepalived是模块化设计,不同模块复杂不同的功能,下面是keepalived的组件。

Control Plane:

    Keepalived配置通过keepalived.conf文件完成。编译器设计用于解析。解析器使用关键字树层次结构来使用特定处理程序映射每个配置关键字。中央多级递归函数读取配置文件并遍历关键字树。在解析期间,配置文件被转换为内部存储器表示。

调度程序 - I / O多路复用器:

    所有事件都安排在同一个进程中。Keepalived是一个单一的过程。

    Keepalived是一种网络路由软件,它对I / O非常封闭。这里使用的设计是一个中央选择(...),负责安排所有内部任务。不使用POSIX线程库。该框架提供了自己的线程抽象,针对网络目的进行了优化。

Memory Mngt(内存管理):

    该框架提供对一些通用内存管理功能的访问,例如分配,重新分配,发布......这个框架可以用于两种模式:normal_mode和debug_mode。

    使用debug_mode时,它提供了一种消除和跟踪内存泄漏的强大方法。这个低级env通过跟踪分配内存并释放来提供缓冲区欠载保护。使用的所有缓冲区都是固定长度的,以防止最终的缓冲区溢出。

Core components(核心组件):

    是keepalived的核心,复杂主进程的启动和维护,全局配置文件的加载解析等。

    该框架定义了所有代码中使用的一些通用和全局库。这些库是:html解析,链接列表,计时器,向量,字符串格式化,缓冲区转储,网络工具,守护程序管理,pid处理,低级TCP层4。这里的目标是将代码分解为最大限度,以尽可能地代码重复以增加模块性。

WatchDog:

    该框架提供子进程监控(VRRP和健康检查)。每个子进程都接受与其自己的监视器unix域套接字的连接。父进程向此子unix域套接字发送“hello”消息。Hello消息使用父端的I / O多路复用器发送,并使用子端的I / O多路复用器接收/处理。如果父检测到损坏的管道,则在子项仍然存活时使用sysV信号进行测试并重新启动它。

Checkers:

    这是主要的Keepalived功能之一,Checkers负责realserver healthchecking。

    包括了各种健康检查方式,以及对应的配置的解析包括LVS的配置解析

    检查器测试如果realserver处于活动状态,则此测试以二进制决策结束:从LVS拓扑中删除或添加realserver。内部检查器设计是实时网络软件,它使用完全多线程的FSM设计(有限状态机)。此检查器堆栈提供符合layer4到layer5 / 7测试结果的LVS拓扑操作。它在由父进程监视的独立进程中运行。

IPVS包装器:

    借助于Checkers实现后端lvs主机的健康状态检测。

    此框架用于将规则发送到内核IPVS代码。它提供Keepalived内部数据表示和IPVS rule_user表示之间的转换。它使用IPVS libipvs来保持与IPVS代码的通用集成。来自LinuxVirtualServer.org OpenSource Project的Wensong提供的Linux内核代码。

IPVS:

    为lvs生成ipvs规则的组件,是内核级别的。

System call:

    在VRRP框架中,它提供了在协议状态转换期间启动额外脚本的能力。系统调用完成分叉进程,以便不会影响全局调度计时器。

keepalived相关进程

keepalived启动后会有三个进程

    PID

    111 Keepalived <-- Parent process monitoring children

    112 \_ Keepalived <-- VRRP child

    113 \_ Keepalived <-- Healthchecking child

    父进程:内存管理,子进程管理等等

    子进程:VRRP子进程

    子进程:healthchecker子进程

两个子进程都被系统WatchDog看管,两个子进程各自负责自己的事。

healthchecker子进程负责检查各自服务器的健康程度,例如HTTP,LVS等等,如果healthchecker子进程检查到MASTER上服务不可用了,就会通知本机上的兄弟VRRP子进程,让他删除通告,并且去掉虚拟IP,转换为BACKUP状态。

keepalived脑裂问题

根据上述工作原理知道, 备节点接收不到报文时, 如两者间的网络不通了, 备节点就会启动接管程序接管主节点的资源, 对外提供服务, 表现形式就是备节点上出现了虚拟IP, 此时主节点也是持有虚拟IP的.

只要有虚拟IP存在, 就不可能完全规避这个问题. 也就是没有虚拟IP了, 就没有脑裂了, 那么节点又如何向外提供服务呢?

推荐自己写脚本

写一个while循环,每轮ping网关,累计连续失败的次数,当连续失败达到一定次数则运行service keepalived stop关闭keepalived服务。

如果发现又能够ping通网关,再重启keepalived服务。最后在脚本开头再加上脚本是否已经运行的判断逻辑,将该脚本加到crontab里面。

keepalived脑裂原因

一般来说脑裂问题有以下这几种原因:

高可用服务器对之间心跳线链路发生故障,导致无法正常通信

心跳线坏了(包括断了,老化)、

网卡及相关驱动坏了,IP配置及冲突问题(网卡直连)

心跳线之间的设备故障(网卡及交换机)、

仲裁的机器出现问题(才用仲裁的方案)

高可用服务器上开启了iptables防火墙,阻止了心跳传消息输

高可用服务器上心跳网卡地址等信息配置不正确,导致发送心跳失败

其他服务配置不当的原因,如心跳方式不同,心跳广播冲突,软件bug等

提示keepalive配置里同一VRRP实例如果virtual_router_id两端参数配置不一致,也会导致脑裂问题

keepalived脑裂方案

在实际生产环境中,我们从以下方面防止脑裂:

同时使用串行电缆和以太网电缆连接、同时使用两条心跳线路,这样一条线路断了,另外一条还是好的,依然能传送心跳消息;

当检查脑裂时强行关闭一个心跳节点(这个功能需要特殊设备支持,如stonith、fence)相当于备节点接收不到心跳消息,通过单独的线路发送关机命令关闭主节点的电源;

做好对脑裂的监控报警;

利用服务注册机制避免脑裂发生。

常见解决方案:

如果开启防火墙,一定要让心跳消息通过,一般通过允许IP段的形式解决

可以拉一条以太网网线或者串口线作为主备节点心跳线路的冗余

开发检测程序通过监控软件检测脑裂

Keepalived优缺点

keepalived与zookeeper都可以用来实现高可用,高可用一般跟负载均衡会一起考虑,所以通常也会考虑到相应的负载均衡能力。

以下是Keepalived与Zookeeper的对比:

Keepalived:

    优点:简单,基本不需要业务层面做任何事情,就可以实现高可用,主备容灾。而且容灾的宕机时间也比较短。

    缺点:也是简单,因为VRRP、主备切换都没有什么复杂的逻辑,所以无法应对某些特殊场景,比如主备通信链路出问题,会导致脑裂。同时,keepalived也不容易做负载均衡。

zookeeper:

    优点:可以支持高可用,负载均衡。本身是个分布式的服务。

    缺点:跟业务结合的比较紧密。需要在业务代码中写好ZK使用的逻辑,比如注册名字。拉取名字对应的服务地址等。

keepalived配置文件

keepalived有三类配置区域

注意:不是三种配置文件,是一个配置文件里面三种不同类别的配置区域

    全局配置(Global Configuration)

    VRRPD配置

    LVS配置

全局定义(global definition)配置范例:

! Configuration File for keepalived

global_defs {

router_id pg_xc1 #主备机必须不一样

script_user postgres #如果是涉及到pg数据库的相关操作,则需要选择pg用户

enable_script_security

}

vrrp_script check_pg_alived {

script “/etc/keepalived/check_pg.sh“ #检查pg数据库状态的脚本,主要靠这个判断是否进行主备切换

interval 5

weight 30 #很重要,判断主备切换的权重

fall 3 # require 3 failures for KO

}

VRRPD配置范例:

vrrp_instance VI_1 {

state BACKUP #BACKUP 必须大写

nopreempt #no preempt为非抢占模式

interface enp0s8 #vip使用的网络接口

virtual_router_id 10 #主备必须一样

priority 80 #设置节点的优先级,跟weight值组合使用,决定选择哪个为主

advert_int 1

authentication {

auth_type PASS

auth_pass abcdefgh

}

VRRPD配置范例(续):

track_script {

check_pg_alived

}

virtual_ipaddress {

192.168.18.100 #vip

}

notify_master “/etc/keepalived/failover.sh“ #当节点成为master时,执行的脚本

notify_fault “/etc/keepalived/fault.sh“ #节点出现故障,执行的脚本

}

Keepalived脚本编写

1、脚本要放在/etc/keepalived目录下,否则无法切换,可能是基于安全的原因。

2、脚本的权限很重要,权限太多执行不成功,一般为755

监控脚本check_pg.sh,对主从PG 进行状态监控。

#!/bin/bash

export PGDATABASE=postgres

export PGPORT=1922

export PGUSER=postgres

export PGHOME=/usr/local/pg12.2

export PATH=$PGHOME/bin:$PATH:$HOME/bin

PGMIP=127.0.0.1

LOGFILE=/etc/keepalived/log/pg_status.log

SQL1='SELECT pg_is_in_recovery from pg_is_in_recovery();'

SQL2='update sr_delay set sr_date = now() where id =1;'

SQL3='SELECT 1;'

db_role=`echo $SQL1 | $PGHOME/bin/psql -d $PGDATABASE -U $PGUSER -At -w`

if [ $db_role == 't' ];

then

echo -e `date +"%F %T"` "Attention1:the current database is standby DB!" >> $LOGFILE

exit 0

fi

# 备库不检查存活,主库更新状态

echo $SQL3 | psql -p $PGPORT -d $PGDATABASE -U $PGUSER -At -w

if [ $? -eq 0 ] ;

then

echo $SQL2 | psql -p $PGPORT -d $PGDATABASE -U $PGUSER -At -w

echo -e `date +"%F %T"` "Success: update the master sr_delay successed!" >> $LOGFILE

exit 0

else

echo -e `date +"%F %T"` "Error:Is the server is running?" >> $LOGFILE

exit 1

fi

切换脚本failover.sh,主库宕机后,keepalived调用执行切换脚本。

#!/bin/bash

export PGPORT=1922

export PGUSER=postgres

export PG_OS_USER=postgres

export PGDATA=/usr/local/pg12.2/data

export PGDBNAME=postgres

export LANG=zh_CN.UTF-8

export PGPATH=/usr/local/pg12.2/bin

export PATH=$PATH:$PGPATH

PGMIP=127.0.0.1

LOGFILE=/etc/keepalived/log/failover.log

# master-to-slave delay

sr_allowed_delay_time=10

SQL1='select pg_is_in_recovery from pg_is_in_recovery();'

SQL2="select sr_date as delay_time from sr_delay where now()-sr_date < interval '60';"

db_role=`echo $SQL1 | psql -At -p $PGPORT -U $PGUSER -d $PGDBNAME -w`

db_sr_delaytime=`echo $SQL2 | psql -p $PGPORT -d $PGDBNAME -U $PGUSER -At -w`

SWITCH_COMMAND='pg_ctl promote -D $PGDATA'

# slave switchover to master if delay large than specical second

if [ $db_role == f ];then

echo -e `date +"%F %T"` "Attention:The current postgreSQL DB is master database,cannot switched!" >> $LOGFILE

exit 0

fi

if [ $db_sr_delaytime -gt 0 ];then

echo -e `date +"%F %T"` "Attention:The current master database is health,the standby DB cannot switched!" >> $LOGFILE

exit 0

fi

echo $db_sr_delaytime

if [ -z $db_sr_delaytime ];then

echo -e `date +"%F %T"` "Attention:The current database is statndby,ready to switch master database!" >> $LOGFILE

pg_ctl promote -D $PGDATA

sed -i 's/primary_conninfo/#primary_conninfo/' $PGDATA/postgresql.auto.conf

pg_ctl restart -D $PGDATA

elif [ $? eq 0 ];then

echo -e `date +"%F %T"` "success:The current standby database successed to switched the primary PG database !" >> $LOGFILE

exit 0

else

echo -e `date +"%F %T"` "Error: the standby database failed to switch the primary PG database !,pelease checked it!" >> $LOGFILE

exit 1

fi

脚本fault.sh,keepalived 进入错误状态时执行的脚本。

#!/bin/bash

LOGGFILE=/etc/keepalived/log/pg_db_fault.log

PGPORT=1922

PGMIP=10.10.10.111

echo -e `date +"%F %T"` "Error:Because of the priamry DB happend some unknown problem,So turn off the PostgreSQL Database!" >> $LOGFILE

PGPID="`netstat -anp|grep $PGPORT |awk '{printf $7}'|cut -d/ -f1`"

service keepalived stop

kill -9 $PGPID

if [ $? eq 0 ];then

echo -e `date +"%F %T"` "Error:Because of the priamry DB happend some unknown problem,So turn off the PostgreSQL Database!" >> $LOGFILE

service keepalived stop

exit 1

fi

Keepalived配置文件(备)

备库配置:

1、把master的keepalived.conf文件和scripts目录复制到备机。

2、修改keepalived.conf的router_id为pg_xc2,priority为80即可。

keepalived启动及状态查看

1、MASTER启动keepalived 服务器

# service keepalived start

2、MASTER查看keepalived 状态

# service keepalived status

3、查看后台日志

# tail -f /var/log/messages

4、查看虚拟ip(ifconfig看不到虚拟IP):

# ip addr

Keepalived主备切换

1、把主库给停掉

在原来的主节点可以看到报错信息/var/log/message

2、此时第三方主机通过vip连接到的是新的主库数据库(说明vip和备库切换到主库成功)。

3、备库切换到主库,需要额外操作完成所有切换(或者在切换脚本实现)

    3.1、修改postgresql.auto.conf中的内容,屏蔽掉之前当作备库时的配置,否则还是名义上的备库。

    3.2、重启实例

    pg_ctl restart

4、原主库变成备库需要手动下面的操作(需要手动操作)

    4.1、编辑standby.signal文件

    primary_conninfo = 'host=pg-xc2 port=1922 user=repl password=repl options=''-c wal_sender_timeout=5000'''

    restore_command = 'cp /home/postgres/arch/%f %p'

    archive_cleanup_command = 'pg_archivecleanup /home/postgres/arch %r'

    standby_mode = on

    4.2、编辑postgresql.auto.conf

    primary_conninfo = 'host=pg-xc2 port=1922 user=repl password=repl options=''-c wal_sender_timeout=5000'''

    restore_command = 'cp /home/postgres/arch/%f %p'

    archive_cleanup_command = 'pg_archivecleanup /home/postgres/arch %r'

    standby_mode = on

    4.3、启动数据库

    $ pg_ctl start

    4.4、查看状态,并且通过第三方通过vip登录时,此时登录的是主库。

    select * from pg_is_in_recovery();

Keepalived主备竞选规则

Keepalived的主备角色是可以改变的,其改变策略是:

1、如果weight值设置为正整数,当主库的vrrp_script脚本执行成功,其权值为priority+weight,而备库的权值为priority+weight的值。那么此时主库的和大于备库的和。

2、如果weight值设置为正整数,当主库的vrrp_script脚本执行失败,其权值为priority设置的值;而备库的权值为priority+weight,如果其和大于主库的priority,则备库会变成主库。

注意weight设置的值必须要大于主备priority之间的差。比如:主库priority设为100,备库priority设为80,weight则要设置大于100-80=20的差。

通过观察/var/log/messages可以看到权值的变化。

keepalived切换模式

keepalived工作模式分为抢占和非抢占模式:

抢占模式:

    通过优先级(priority)来决定谁是master,优先级高的为master,拥有虚拟IP。

    这种模式有一个问题就是当原主节点从故障中恢复后会重新获得master角色抢占虚拟IP,这在有些场景可能会有问题(例如需要数据同步的场景,恢复后需要先同步数据)。

    抢占模式配置:preempt

非抢占模式:

    发生故障才切换(比如keepalived进程中断),否则不切换。切换测试时先停止主库,再关闭keepalived进程。

    非抢占模式配置:no preempt

切换模式选择规则

如果是要实现主库和vip都在同一台主机的目标,那么应该选择非抢占模式,这样子虽然主库中断,只要keepalived进程还在,则不会发生主库切换和vip切换。虽然切换响应时间受到影响,但是保证通过VIP都能够连接主库上。

如果是抢占模式,会出现以下情况:

1、A是主库(拥有vip),B是备库

2、A主库关闭,B变成主库(抢到vip) #此时没有问题。

3、A备库启动(根据抢占模式,抢到vip),B还是主库(但是vip被抢占) #此时通过vip就会访问到备库。

4、如果一定要提高数据库故障切换响应时间,可以配置为抢占模式,但是当备库(原来的主库)启动前,得降低该主机的优先级模式。也就是保证主库所在的优先级要高,vip不会被抢占。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot 3 极速搭建OAuth2认证框架

本篇环境 Java 17Spring Boot 3.2.3Spring Authorization Server 1.2.3开发工具 SpringToolSuite4Spring Boot 3.2.3 需要JDK 17及之上的版本。 项目初始化 项目可以使用Spring的初始化器生成, 也可以创建一个Maven类型的项目。 项目创建后的目录结构如下: 项目配置 使用 …

OpenHarmony游戏应用程序-实现的一个手柄游戏

介绍 本篇Codelab是基于TS扩展的声明式开发范式编程语言&#xff0c;以及OpenHarmony的分布式能力实现的一个手柄游戏。 说明&#xff1a; 本示例涉及使用系统接口&#xff0c;需要手动替换Full SDK才能编译通过。 完成本篇Codelab需要两台开发板&#xff0c;一台开发板作为游…

罗德与施瓦茨CMA180电信无线电测试仪

181/2461/8938产品概述&#xff1a; R&S CMA180 是适用于在 100 kHz 至 3 GHz 范围内操作的无线电系统的无线电通信测试仪。其技术完全基于数字信号处理及先进计算。 简介&#xff1a;R&S CMA180 无线电通信测试仪 R&SCMA180 是适用于在 100 kHz 至 3 GHz 范围内…

电商系统秒杀二 秒杀场景下如何进行限流

本章学习内容 1、在秒杀页面&#xff0c;客户点击秒杀后&#xff0c;在前台弹出一个验证码&#xff0c;需要用户输入验证码才能往后端发送请求&#xff0c;这样能够错开秒杀下单的时间。 2、通过验证码&#xff0c;对后台下单请求进行保护&#xff0c;防止刷单&#xff0c;即防…

通过JWT完成token登录验证

前言 什么是JWT&#xff1f; 全称是JSON Web token&#xff0c;是用于对应用程序上的用户进行身份验证的标记&#xff0c;使用 JWTS 的应用程序不再需要保存有关其用户的 cookie 或其他session数据 使用JWT的优势 提高了程序的可伸缩性&#xff0c;也极大的提高了应用程序的安全…

2024蓝桥杯每日一题(单调队列)

备战2024年蓝桥杯 -- 每日一题 Python大学A组 试题一&#xff1a;单调栈 试题二&#xff1a;滑动窗口 试题三&#xff1a;子矩阵 试题四&#xff1a;最大子序和 试题一&#xff1a;单调栈 【题目描述】 给定一个长度为 N 的整数数列&#xff0c;输出每…

第十四届蓝桥杯JavaB组省赛真题 - 幸运数字

进制转换可以参考如下的十进制&#xff0c;基本一样的&#xff0c;只是把10变成了其他数字&#xff0c; sum就是各个数位之和 public static int myUtil(int n) {int sum 0;while(n > 0) {sum n % 10;n / 10;}return sum;} 注意&#xff1a; 如果写在同一个类里面&…

基于javaSpringboot+mybatis+layui的装修验收管理系统设计和实现

基于javaSpringbootmybatislayui的装修验收管理系统设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留…

Java安全 反序列化(5) CC6链原理分析

Java安全 反序列化(5) CC6链原理分析 CC6学习的目的在于其可以无视jdk版本&#xff0c;这条链子更像CC1-LazyMap和URLDNS链子的缝合版 文章目录 Java安全 反序列化(5) CC6链原理分析前言一.CC6的原理和实现以及易错点我们如何实现调用LazyMap.get()方法一个易错点 二.完整CC6P…

亚马逊服务器ssh以及scp

ssh awspass.pem为创建服务器时创建的密钥&#xff0c;ubuntu用户 ssh -i "awspass.pem" ubuntuipscp scp -i "awspass.pem" -r dist/* ubuntuip:/home/ubuntu/

macOS下Java应用的打包和安装程序制作

文章目录 macOS应用程序结构Java应用打包JavaAppLauncherjpackage其它相关JDK命令附录JavaAppLauncher源码链接macOS应用程序结构 macOS通常以dmg或pkg作为软件发行包,安装到/Applications下后,结构比较统一。 info.plist里的CFBundleExecutable字段可以指定入口,如果不指定…

使用uniapp 的 plus.sqlite 操作本地数据库报错:::table xxx has no column named xxxx

背景&#xff1a; 1、使用uniapp 的 plus.sqlite 进行APP本地数据库操作 2、SQLite 模块用于操作本地数据库文件&#xff0c;可实现数据库文件的创建&#xff0c;执行SQL语句等功能。 遇到&#xff1a;在之前创建的表上进行新增字段的操作时候&#xff0c;出现问题&#xff1a…

蓝桥杯 2022 省B 砍竹子

思路&#xff1a; 非常明显&#xff0c;这题是个贪心。因为这题是求最小操作次数&#xff0c;而且每次操作都会变小&#xff0c;所以肯定要优先操作大的元素&#xff0c;这样它变小之后才可能和其它元素一起操作以减少操作次数。 所以&#xff1a;建立两个数组&#xff0c;一…

Canine IP-10/CXCL 10 ELISA试剂盒上新

科研用Canine IP-10/CXCL 10 ELISA试剂盒重磅来袭&#xff0c;将在免疫学、癌症研究与神经科学等多个领域助力各位老师们的研究&#xff01; 图1&#xff1a;犬IP-10/CXCL10结构预测&#xff08;图片来源&#xff1a;UniProt&#xff09; C-X-C基序趋化因子(C-X-C motif chemok…

绿色节能|AIRIOT智慧建材能耗管理解决方案

建材供应是建筑业不可或缺的一个重要环节&#xff0c;在环保和企业可持续发展的双重需求下&#xff0c;建材生产商对建材生产过程中的能耗掌握和能耗管理尤其关注。但在实际生产和运营过程中&#xff0c;传统的建材能耗管理方式往往存在如下痛点&#xff1a; 用户管理权限不完善…

什么是单点登录?

单点登录&#xff08;Single Sign On&#xff0c;简称 SSO&#xff09;简单来说就是用户只需在一处登录&#xff0c;不用在其他多系统环境下重复登录。用户的一次登录就能得到其他所有系统的信任。 为什么需要单点登录 单点登录在大型网站应用频繁&#xff0c;比如阿里旗下有淘…

Unity发布webgl之后打开PDF文件,不使用js,不和浏览器交互

创建一个按钮&#xff0c;然后点击就会打开 在webgl下要使用这样的路径拼接&#xff0c;不然就会报错。 btnBook.onClick.AddListener(() >{var uri new System.Uri(Path.Combine(Application.streamingAssetsPath "/Books", "文档.pdf"));Debug.Log…

短视频矩阵系统---php7.40版本升级自研

短视频矩阵系统---php7.40版本升级自研 1.部署及搭建 相对于其他系统&#xff0c;该系统得开发及部署难度主要在各平台官方应用权限的申请上&#xff0c;据小编了解&#xff0c;目前抖音短视频平台部分权限内侧名额已满&#xff0c;巧妇难为无米之炊&#xff0c;在做相关程序…

Xilink 简单双口ram ip的读写仿真

简单双口RAM有两个端口Port A和port B,其中Port A用于写数据,Port B用于读数据,读写接口可以独立时钟工作。这一点和真双口RAM是有区别的,真双口RAM的A B两个Port都可以进行读写操作。 RAM是FPGA中重要的数据结构,可用于数据的缓存和跨时钟域信号处理。本文就xilin…

Java项目:71 ssm基于ssm+vue的外卖点餐系统+vue

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 系统功能 系统分为前台订餐和后台管理&#xff1a; 1.前台订餐 用户注册、用户登录、我的购物车、我的订单、商品列表 2.后台管理 商品管理&#xf…