Elasticsearch 备份和恢复功能 Elasticsearch 是一个分布式搜索和分析引擎,广泛应用于各种场景,如日志分析、全文搜索和实时数据处理。在使用 Elasticsearch 时,数据的安全和可用性至关重要。本文将详细讲解 Elasticsearch 的备份和恢复功能,包括快照、恢复和灾难恢复策略。
快照 快照是 Elasticsearch 集群数据的一种备份方法。它可以将集群中的所有索引(或部分索引)备份到一个远程存储系统,如文件系统、Amazon S3、Hadoop HDFS 等。快照是增量的,这意味着只有在上次快照之后发生更改的数据才会被备份。这使得快照操作非常高效,可以定期执行以确保数据安全。
创建快照存储库 在创建快照之前,需要先设置一个快照存储库。存储库是一个远程存储系统,用于存储快照数据。以下是一个使用文件系统作为存储库的示例:
PUT /_snapshot/my_backup { "type": "fs", "settings": { "location": "/mnt/backups/my_backup" } } 这个请求将创建一个名为 my_backup 的存储库,使用文件系统作为存储介质,并将快照数据存储在 /mnt/backups/my_backup 目录下。
创建快照 创建快照的过程非常简单。以下是一个创建名为 snapshot_1 的快照的示例:
PUT /_snapshot/my_backup/snapshot_1?wait_for_completion=true 这个请求将创建一个名为 snapshot_1 的快照,包含集群中的所有索引。wait_for_completion=true 参数表示请求将等待快照操作完成。如果您只想备份部分索引,可以使用以下请求:
PUT /_snapshot/my_backup/snapshot_1 { "indices": "index_1,index_2", "wait_for_completion": "true" } 这个请求将只备份名为 index_1 和 index_2 的索引。
查看和管理快照 要查看存储库中的所有快照,可以使用以下请求:
GET /_snapshot/my_backup/_all 这将返回一个包含所有快照信息的 JSON 对象。
要查看单个快照的详细信息,可以使用以下请求:
GET /_snapshot/my_backup/snapshot_1 这将返回名为 snapshot_1 的快照的详细信息。
准备 首先需要卸载掉centos7中自带的mariadb,先执行
rpm -qa | grep mariadb # 查看系统中安装的mariadb 如果有输出,则执行,否则进入第一步 ,开始下载mysql安装包
rpm -e --nodeps 【上面命令出现的文件名】 # 删除系统自带的mariadb 查看是否安装 libaio yum list installed | grep libaio 没有安装则执行安装命令
yum install -y libaio 一、下载mysql8.0.35安装包 官方下载地址:MySQL :: Download MySQL Community Server
这里我选择的是.xz格式的包。
这里有一个坑,注意看图中每个包名中都带有(glibc 2.28),需要去linux控制台中执行下面的命令确认自己的glibc版本,很重要!!!很重要!!!很重要!!!
ldd --version # 查看自己linux的glibc版本号 这里可以看到我的版本号是2.17
所以在下载glibc为2.17的包,下载页面向下翻就可以找到。
可能有人不确定自己的系统是64位还是32位,执行下面命令去确定哈。
uname -m # 查看系统是64位还是32位 二、解压安装包 下载好以后,使用xshell或者其它工具把包放在linux的 /usr/local 下并解压,因为我下载的是.xz格式的包,所以执行下面命令解压。
cd /usr/local tar -Jxvf /usr/local/mysql-8.0.35-linux-glibc2.17-x86_64.tar.xz 三、文件夹重命名 mv mysql-8.0.35-linux-glibc2.17-x86_64 mysql8 # 文件夹重命名 rm -rf mysql-8.0.35-linux-glibc2.17-x86_64.tar.xz # 删除压缩文件 四、添加path环境变量 在linux中添加path变量的目的是为了能在全局使用mysql命令。
近段时间,电视家不能用了,好吧,自己开发一个APP。其实也不是开发,而是基于现有的播放器核心自己封装一个,只要能够非常方便操作观看电视就好。
当然,前提是要有节目源,这个我早已完成:通过OpenWRT用udpxy将IPTV信号转换为HTTP单播协议融合到了家里的局域网中。
基于哪一款播放器核心来封装,其实有很多选择:VLC、ExoPlayer、IjkPlayer、安卓自带的控件VideoView。
我首先使用的是VLC,因为这款播放器我用得最多,在Windows平台上,我也用C#基于它封装了一个播放器,平时坐在电脑前一边做事,一边通过这个封装的播放器看看电视。
封装的关键步骤为:
1、按常规步骤新建android项目,Empty View类型的项目就好。
2、为项目添加VLC支持库。修改 build.gradle.kts 文件,在依赖项中添加:
dependencies {
implementation("org.videolan.android:libvlc-all:3.5.1")
……
}
这里的版本号可以适时修改。
3、给项目APP授予网络访问的权限。在AndroidManifest.xml中添加:
<uses-permission android:name="android.permission.INTERNET" />
4、添加播放器的显示组件。在APP主界面的视图配置文件activity_main.xml中添加:
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
5、声明初始化基于VLC的播放器核心组件,并将视频显示关联到控件:
ArrayList<String> options = new ArrayList<>();
options.add("--rtsp-tcp");
options.add("--live-caching=200");
LibVLC libVLC = new LibVLC(this, options);
MediaPlayer mediaPlayer = new MediaPlayer(libVLC);
SurfaceView surfaceView = findViewById(R.id.surfaceView);
mediaPlayer.getVLCVout().setVideoView(surfaceView);
mediaPlayer.getVLCVout().setWindowSize(surfaceView.getWidth(), surfaceView.getHeight());
surfaceView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
前言
DSP各种模块的使用,基本上就是 GPIO复用配置、相关控制寄存器的配置、中断的配置。本文主要记录本人对ADC模块的学习笔记。TMS320F28377D上面有24路ADC专用IO,这意味着不需要进行GPIO复用配置。 只需要考虑相关控制寄存器和中断的配置。看代码请直接跳到最后。
单端模式/差分模式
在放代码之前,先谈谈TMS320F28377D的ADC里面非常容易搞蒙的一点:单端模式/差分模式
根据TMS320F28377D 的reference的介绍(pg:1554),ADC模块有以下特性 :
差分信号转换 仅限16位模式
单端信号转换 仅限12位模式
单端的话,就能有16通道(12位)| 差分的话,就能有8通道(16位)。
很多人都对差分模式下DSP的代码应该如何编写还不够理解,相信看了下面这个帖子会有启发。TMS320F28388D: 16位差分采样 - C2000™︎ 微控制器论坛 - C2000 微控制器 - E2E™ 设计支持 (ti.com)
我怕帖子被删除了,还是复述点关键的东西吧。 下表不仅给出了单端/差分在16位模式下的解算方式,也间接说明了单端也并非是 12-bit mode only,单端也是可以用16位的。
而下面两条评论,则清晰的解释了差分模式下,如何得到ADC的采集结果 最后,结合一张硬件原理图,基本上已经一目了然了 代码理解 下面给出ADC控制寄存器的相关配置代码,并进行解释。
EALLOW; AdcaRegs.ADCCTL2.bit.PRESCALE = 6; // Set ADCCLK divider to /4 AdcSetMode(ADC_ADCA, ADC_RESOLUTION_16BIT, ADC_SIGNALMODE_SINGLE); AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1; AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; DELAY_US(1000); EDIS; AdcaRegs.ADCCTL2.bit.PRESCALE = 6;
本行代码是ADC的时钟预分频,参考手册pg1597可以看到,6表示4分频,此行代码是参考Ti的官方例程里面的代码。
AdcSetMode(ADC_ADCA, ADC_RESOLUTION_16BIT, ADC_SIGNALMODE_SINGLE);
此行代码是设置ADC模块的A组ADCA(还有ADCB、ADCC、ADCD)的分辨率,和单端/差分模式。正文开篇也提到了,单端模式也是可以使用16位的分辨率的。 当然我们也可以把ADCA配置成差分模式,然后使用16位的分辨率,
AdcSetMode(ADC_ADCA, ADC_RESOLUTION_16BIT, ADC_SIGNALMODE_DIFFERENTIAL);
前言
在对学习F28034过程中发现网上很少有对其工程模板配置以及使用F28034驱动其他模块的教程。并且考虑创建一个F28034通用的CCS工程模板,以简化新项目的创建过程。通过制作一个模板,可以节省时间和减少繁琐的工程搭建步骤。在需要新项目时,只需复制模板并进行相应配置即可快速启动开发工作。所以笔者在这对F28034工程模板的配置进行记录并且使用F28034点亮LED进行程序测试。
(本文仅供学习交流,如有错误或有更好的解决方案,欢迎相互交流讨论。)
一、TMS320F28034是什么?
TMS320F28034指的是德州仪器(Texas Instruments)推出的一款数字信号处理器(Digital Signal Processor,DSP)型号(后称F28034)。它属于TI的C2000系列,是专门设计用于实时控制应用的DSP芯片。
F28034具有高性能、低功耗、丰富的外设接口等特点,适用于各种需要高精度实时控制的场合,比如电机控制、逆变器、电源管理等应用领域。它采用了先进的处理器内核和数字信号处理器技术,具备强大的计算能力和灵活的控制功能。
这款DSP通常会配合TI提供的开发工具和软件库来进行程序开发和调试,以满足各种实时控制系统的需求。
二、所做准备工作 1、所需软硬件 (1)Code Composer Studio 7.2.0 (2)TMS320F28034核心板或开发板 2、所需配置文件 (1)TI官方提供的配置文件 三、操作流程 1、打开CCS进行工程建立 (1)工程建立(路径应当不包含中文) ①路径选择 路径选择好了以后点击OK。
②新建工程
点击File→New→CCS Project或者键盘按下快捷键Shift+Alt+N→CCS Project效果一样
③工程配置 按照如图①-⑤顺序进行选择,其中①②③型号尽量选对,这里开发板我以TMS320F28034芯片,仿真器以Texas Instruments XDS100v2 USB Debug Probe型号为例。
⑤可以选择带有main.c的那个选项(Empty Project(with main.c))
然后点击Finish。(这里我已经建立过工程,所以Finish无法点击)
(2)工程模板配置 ①文件夹建立 在前文创建的工程文件夹F28034_Learn下建立一个文件夹F28034_Lib(也可以是其他英文字符组成的名字)
在F28034_Lib文件夹下创建文件夹cmd、include、source(也可以是其他英文字符组成的名字)。其中,include放.h文件、source放.c文件。
在工程中可以看到已经有该文件夹。
②文件导入 将提供的DSP2803x_headers文件夹下的cmd文件夹中的DSP2803x_Headers_nonBIOS.cmd文件放入我们创建的cmd文件夹中。
打开DSP2803x_headers、DSP2803x_common文件夹中的include文件夹,选中所有的.h文件导入我们创建的include文件夹中,总共31个.h文件。
同样,选中DSP2803x_headers、DSP2803x_common文件夹中的source文件夹将,其中所有的.c文件导入我们创建的source文件夹中,总共25个.c文件。
③工程选项配置 鼠标右击工程F28034_Learn→Properties
按照图片中在最左侧选中Include Options→…→选中include(导入放.h文件的文件夹路径)按照图片步骤进行最后点击OK
④最后需要更改下下载.cmd文件 和③一样鼠标右击工程F28034_Learn→Properties
选中General→在Linker command file选中DSP型号,我这里需要下到Flash中所以选中F28034.cmd
⑤在main.c文件写入程序 #include "DSP2803x_Device.h" // DSP2803x Headerfile Include File
#include "DSP2803x_Examples.h" // DSP2803x Examples Include File
第七章: 图像平滑处理 1、什么是图像平滑处理
图像平滑处理就是,将图像中与 周围像素点的像素值差异较大的像素点 调整成 和周围像素点像素值 相近的值。
例如:
2、为什么要进行平滑处理?
因为图像在采集(生成)、传输、处理的过程中常常会存在一定的噪声干扰,比如,在图像拍摄的时候,也就是图像生成的时候,实际中往往会出现比如镜头污染、光线较强、较弱、大气折射、镜头角度等问题,导致拍摄出来的图片某些像素亮度变化过大,比如过亮或者过暗,导致人眼看到的图像画面不清晰,也就是图像有噪声,影响画质。为了抑制这种噪声,改善图像质量,我们就要对图像进行平滑处理。
说明:图像经过平滑处理smoothing后,虽然可以抑制一些噪音,但同时也会把图像中的边缘线条弄模糊blurring了。
3、如何进行平滑处理?
用滤波器(filtering)过滤掉某些波,保留另一些波。
滤波器是物理学中的概念,是物理学中对波的处理方式,有非常深入的研究和多种处理波的方法。
我们拿物理学中的这个方法用到图像处理上,就叫图像滤波。在图像领域,实现图像滤波的滤波器我们叫滤波核filter,也叫卷积核。 图像滤波是图像处理和计算机视觉中最常用、最基本的操作。
我们首先要明白,计算机视觉不是让人眼去看图片的,是让计算机去看图片的,让它去识别图像中特定物体、去检测图像中的特定目标、去分割图像中特定的目标,而计算机看图片和人眼看图片完全不是一回事,人眼看到的是图像,计算机看到的是一个数字矩阵。而让计算机去"图像识别",就是让它从一大堆数字中找出规律。而我们对图像进行的一些处理是便于计算机找出这个规律。
图像滤波可以实现对图像的各种处理,比如实现图像的平移、旋转、镜面、分割、检测等等几乎所有的处理方式。本章中对图像进行平滑处理更是可以通过图像滤波去实现。
所以,如果我们想对一张图像进行滤波处理,
一是要确定你的滤波核也就是卷积核,包括卷积核的尺寸和卷积核内的数值,其中,尺寸是必须考虑的,而数值有些情况下是不需要考虑的,因为有时我们只需要一个没有数据只有尺寸的核即可);
二是要确定卷积的方式,比如是进行均值运算还是加权运算还是中值运算等等方法;
三是要确定是否要padding以及如果padding,padding就是对图像边缘进行填充,图像边缘的像素点是没法卷积运算的,此时就要特别处理,就是填充,而填充也有多种填充方式比如0填充、常量填充、镜像填充等。
一、均值滤波
用一个只有尺寸没有数值的卷积核去卷积原图像,得到对应位置上的每个像素点的值是被卷积核套住的像素的均值。
API: cv2.blur(img, ksize)
#例7.1 观察均值滤波对图像的处理效果 import cv2 import matplotlib.pyplot as plt img = cv2.imread(r'C:\Users\25584\Desktop\lenaNoise.png') img_blur1 = cv2.blur(img, (5,5)) #使用5x5的卷积核 img_blur2 = cv2.blur(img, (30,30)) #使用30x30的卷积核 fig, axes = plt.subplots(1,3, figsize=(10,5), dpi=100) axes[0].imshow(img[:,:,::-1]) axes[1].imshow(img_blur1[:,:,::-1]) axes[2].imshow(img_blur2[:,:,::-1]) plt.show() 说明:均值滤波的卷积核越大,参与到均值运算中的像素就会越多,也就是当前像素点的值是更多像素点的值的均值,
所以,卷积核越大去噪效果越好,但图像实真也越严重。所以,我们要选择合适尺寸的卷积核,在失真和去噪之间取得平衡。
二、方框滤波
用一个有尺寸有数值的卷积核去卷积原图像。
API: cv2.boxFilter(img, ddepth, ksize [, anchor, normalize, borderType])
文章目录 一、flask扩展二、项目配置1. 直接配置2. 使用配置文件3. 使用环境变量4. 实例文件夹 三、flask命令四、模版和静态文件五、flask和mvc架构 一、flask扩展 flask扩展是指那些为Flask框架提供额外功能和特性的库。这些扩展通常遵循Flask的设计原则,易于集成到flask应用中,并且可以大大加快开发速度。
常用flask扩展:
Flask-SQLAlchemy:操作SQLAlchemy,它是一个强大的关系型数据库框架。
Flask-Migrate:基于Alembic的Flask扩展,用于处理SQLAlchemy数据库迁移。
Flask-WTF:整合了WTForms的Flask扩展,提供表单类和验证功能。
Flask-Login:提供用户会话管理,处理用户登录、登出和记住我功能。
Flask-Mail:提供邮件发送支持。
Flask-RESTful:用于快速开发REST API的Flask扩展。
Flask-HTTPAuth:用于HTTP认证的简单扩展。
Flask-Caching:提供缓存支持,可以与多种后端如Redis、Memcached等配合使用。
Flask-Session:一个Flask扩展,用于服务器端会话管理。
Flask-Admin:提供一个简单的界面来管理数据模型。
Flask-SocketIO:为Flask应用添加WebSocket支持。
Flask-CORS:处理跨源资源共享(CORS),使得你可以在Flask应用中轻松地处理跨域请求。
二、项目配置 1. 直接配置 可以直接在创建 Flask 应用实例后,通过字典的方式对其进行配置:
app = Flask(__name__) app.config['DEBUG'] = True app.config['SECRET_KEY'] = 'your_secret_key' 2. 使用配置文件 在项目目录下创建config.py文件,将配置进行集中管理。
DEBUG = True SECRET_KEY = 'your_secret_key' SQLALCHEMY_DATABASE_URI = 'sqlite:///your-database.db' 然后在应用中加载此文件
import config app = Flask(__name__) app.config.from_object('config') 3. 使用环境变量 使用环境变量来配置Flask应用,能够让你的应用根据运行的环境(如开发环境、测试环境和生产环境)加载不同的配置,而无需更改代码。这样做有助于保护敏感信息,比如数据库的用户名和密码,不被直接存储在源代码中,同时也便于在不同的环境之间迁移应用。
在Unix-like系统(包括Linux和Mac OS X)中,你可以在命令行中设置环境变量,如下:
export YOURAPPLICATION_SETTINGS=/path/to/settings.cfg 在Windows系统中,你可以使用以下命令:
set YOURAPPLICATION_SETTINGS=/path/to/settings.cfg 假设setting.cfg文件中内容为:
linux系统中安装nginx到指定目录 下载要求版本的nginx源码包
上传并解压nginx源码包
# 在/opt/app目录下创建nginx解压安装目录 cd /opt/app mkdir nginx # 切换到解压目录下 cd /opt/app/nginx # 解压 tar -zxvf nginx-1.24.0.tar.gz 编译安装 # 在/opt/app/nginx路径下,进入nginx解压后的目录 cd nginx-1.24.0 # 指定安装位置 ./configure --prefix=/opt/app/nginx # 编译安装 make && make install 检查安装是否成功 # 切换到/opt/app/nginx/sbin路径下, 查看nginx的版本 ./nginx -v 启动nginx # 在/opt/app/nginx/路径下,修改nginx配置文件 vim conf/nginx.conf # 修改80端口(80端口需要root权限) # 在server配置信息中添加upload的配置信息(显示上传的文件时) location /upload { root /opt/app/xxx; } # 在http块中添加server配置信息 server { listen 8084; server_name 127.0.0.1; location / { proxy_pass http://0.0.0.0:8004; # 系统的启动地址 proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_body_buffer_size 2M; # 超过这个值存入临时文件,小于这个值存入内存 client_max_body_size 500M; # 设置上传文件的最大值 client_body_temp_path /opt/app/nginx/client_body_temp; proxy_connect_timeout 300; proxy_read_timeout 300; proxy_send_timeout 300; } } # /opt/app/nginx/路径下,新建client_body_temp文件夹 mkdir client_body_temp # 在/opt/app/nginx/路径下,启动 .
国内 Maven 镜像,你可以将它们添加到你的 Android Kotlin 项目的 build.gradle 文件中,以加快依赖库的下载速度:
中央仓库(Maven Central)镜像
repositories { mavenCentral() maven { url 'https://maven.aliyun.com/repository/central' } } JCenter 镜像:
repositories { jcenter() maven { url 'https://maven.aliyun.com/repository/public' } } Google Maven 仓库镜像:
repositories { google() maven { url 'https://maven.aliyun.com/repository/google' } } Gradle 插件仓库镜像(适用于项目的 build.gradle 文件): buildscript { repositories { google() maven { url 'https://maven.aliyun.com/repository/google' } jcenter() maven { url 'https://maven.aliyun.com/repository/public' } } // ... }
官方文档https://clickhouse.com/docs/en/engines/table-engines
MergerTree引擎家族,只要带MergerTree的就是
MergerTree
ReplicatedMergeTree
ReplicatedAggregatingMergeTree
ReplicatedReplacingMergeTree
ReplicatedSummingMergeTree
ReplacingMergeTree
SummingMergeTree
AggregatingMergeTree
其他引擎
Distributed
Merge
MaterializedView
最佳实践:
4节点的集群,1-2节点为分片1,且1-2互为对方副本,3-4节点为分片2,且3-4互为对方副本,集群配置文件中的子配置项分片权重的配置不用配置会直接使用默认值1即数据平分到2个现有分片,集群配置文件中的子配置项<internal_replication></internal_replication>数据是否同时写入多个副本的配置配置为true即写操作只选一个正常的副本写入数据然后数据的复制工作交给实际需要写入数据的表本身而不是分布式表。
创建Distributed分布式表其中该分布式表使用ReplicatedMergeTree引擎的表作为子表,分布式表不再需要配置sharding_key,数据插入Distributed分布式表后,此时在4个节点上查看到的分布式表数据都是一样的
创建Distributed分布式表其中该分布式表使用ReplicatedMergeTree引擎的表作为子表,分布式表不再需要配置sharding_key,数据插入各个节点的ReplicatedMergeTree引擎子表,此时在4个节点上查看到的分布式表数据是一样的
创建Distributed分布式表其中该分布式表使用MergeTree引擎的表作为子表,数据库插入Distributed分布式表或各个节点的MergeTree引擎子表后,在4个节上看到的分布式表数据不一致,且经常错乱无章
仅仅使用ENGINE = MergeTree()表引擎的话,Clickhouse缺少了两个功能————数据高可用(HA)和横向扩展。HA的目的是为了如果有一个数据副本丢失或者损坏不至于完全丢失数据,至于横向扩展自然是为了提高数据存储能力了。数据高可用(HA)的实现需要使用ReplicatedMergeTree表引擎,横向扩展的实现需要使用Distributed表引擎,Clickhouse github上有一段总结
if your data is too big to fit/ to process on one server - use sharding
to balance the load between replicas and to combine the result of selects from different shards - use Distributed table.
MergeTree表引擎
https://clickhouse.com/docs/zh/engines/table-engines/mergetree-family/mergetree
ENGINE = MergeTree()括号里面没有参数,所以不受宏配置macros的影响。但是ENGINE = MergeTree()有setting选项enable_mixed_granularity_parts,如果您的表里有很大的行,可以开启enable_mixed_granularity_parts这项配置来提升SELECT查询的性能。
MergeTree 系列的引擎被设计用于插入极大量的数据到一张表当中。数据可以以数据片段的形式一个接着一个的快速写入,数据片段在后台按照一定的规则进行合并。相比在插入时不断修改(重写)已存储的数据,这种策略会高效很多。其实就是批量数据快速插入和后台并发处理的两大优势。
Clickhouse集群4节点,在节点1执行如下
输入错误密码报错
root@DAILACHDBUD001:/var/log# clickhouse-client ClickHouse client version 23.4.2.11 (official build). Connecting to localhost:9000 as user default. Password for user (default): Connecting to localhost:9000 as user default. Code: 516. DB::Exception: Received from localhost:9000. DB::Exception: default: Authentication failed: password is incorrect, or there is no user with such name. If you have installed ClickHouse and forgot password you can reset it in the configuration file. The password for default user is typically located at /etc/clickhouse-server/users.
官方文档
https://clickhouse.com/docs/zh/getting-started/tutorial#cluster-deployment
https://clickhouse.com/docs/en/engines/table-engines/special/distributed
https://zookeeper.apache.org/
Clickhouse的优点
列式存储数据库,数据压缩;
关系型、支持SQL;
分布式并行计算,把单机性能压榨到极限;
高可用;数据量级在PB级别。
集群的分片和副本和节点数量的选择,CK officially supports only one shard/replica per node
分片数*副本数=节点数
最佳实践就是3分片2副本6节点
3节点3分片2副本,无法配置起来,会报错DB::Exception: There are two exactly the same ClickHouse instances DAILACHDBUD001:9000 in cluster cluster_3shared2replicas
ClickHouse集群集群部署设置步骤:
在群集的所有机器上安装ClickHouse服务端
在配置文件中设置集群配置
在每个实例上创建本地表
创建一个分布式表,分布式表实际上是一种view,映射到ClickHouse集群的本地表。 从分布式表中执行SELECT查询会使用集群所有分片的资源。 您可以为多个集群指定configs,并创建多个分布式表,为不同的集群提供视图。
备注:也就是说集群的最终目标就是为了能创建分布式表,通过分布式表可以实现读取量发布到各个节点,也是为了能给大表做横向扩展。
集群<cluster_2shared2replicas>配置项对ENGINE = Distributed表和ENGINE = ReplicatedMergeTree表和MergeTree表有效,集群配置项中只对ENGINE = ReplicatedMergeTree表有效。单独的ENGINE = MergeTree仅仅是对表的数据做分片,这样的话Clickhouse缺少了两个功能————数据高可用(HA)和横向扩展。HA的目的是为了如果有一个数据副本丢失或者损坏不至于完全丢失数据,至于横向扩展自然是为了提高数据存储能力了。数据高可用(HA)的实现需要使用ReplicatedMergeTree表引擎,横向扩展的实现需要使用Distributed表引擎,MergeTree表引擎+Distributed表引擎同时使用,只能做分片并把分片分发到不同节点,但是Distributed表查询的总量还是异常
Clickhouse除了提供TCP 9000端口的连接,还提供了HTTP 8123端口的连接http://ip:8123/play
Clickhouse本身没有类似Mongodb一样的Mongos Route Server前端路由实例让整个集群看上去像单一连接点以便前端应用可以透明连接该路由实例,但是可以通过F5或A10提供的负载均衡功能来实现Clickhouse的路由接入,通过负载均衡设置提供的单一地址实现客户端连接到多个不同clickhouse节点
ClickHouse集群环境下,DDL语句的同步使用ZooKeeper来同步,所以在一个节点上create\alter本地表时加上on cluster clustername的话,这张表的表结构就会同时在其他节点上被create\alter
clickhouse集群是非主从结构,各个节点是相互独立的,这点和mongodb不一样。分片(Shard)就是将一份数据分片段存储到多台服务器上,每台服务器只存储这份数据的一部分,在这种架构下,每台服务器被称为一个分片(Shard)。副本(Replica)就是将一份数据冗余存储到多台服务器上。假如4台服务器的集群环境下,2分片2副本的集群策略的话,就是把一份数据分成2个片段来存储,这2个片段都有2份,也就是这一份数据在物理上变成了4个单元,其中4个单元分成2个片段,每个片段的2份的数据是一模一样。
本地表(Local Table)
数据只会存储在当前写入的节点上,不会被分散到多台服务器上。本地表的写入和查询,受限于单台服务器的存储、计算资源,不具备横向拓展能力。
分布式表(Distributed Table)
本地表的集合,它将多个本地表抽象为一张统一的表,对外提供写入、查询功能。当写入分布式表时,数据会被自动分发到集合中的各个本地表中;当查询分布式表时,集合中的各个本地表都会被分别查询,并且把最终结果汇总后返回。分布式表的写入和查询,可以利用多台服务器的存储、计算资源,具有较好的横向拓展能力。ClickHouse集群就是因为分布式表(Distributed Table)而产生的。
Clickhouse集群环境:4节点搭建2分片2副本的实验
1、操作系统的配置
1.1、四节点的IP、服务器名称、OS信息如下
什么是Git Git是一个源代码管理系统,旨在帮助开发人员协同工作。它是一个分布式的版本控制系统,可以有效地将代码库分支、合并和版本控制,同时还可以跟踪文件的更改、修改内容并保留历史记录。Git能够让多个开发人员同时对同一代码库进行协作,同时还可以轻松地管理和组织代码库。Git也可以与多种开发工具和应用程序集成,是当前最受欢迎的版本控制工具之一。
git安装 我们先到Git官网下载Git的安装包,选择你想要的系统版本进行下载,官网地址:Git - Downloads (git-scm.com)
可能会由于特殊原因,下载缓慢的话可以下载我提供的Git压缩包。
如果想要下载特定的历史版本,即可以点击左下角的Older releases,选择Git特定的历史版本进行下载即可 。
根据你的操作系统选择,32位就选32位,64位就选64位 这里我就以Windows为例,点击下载后浏览器会开始下载一个安装包,下载完成后点击安装包开始安装。
一路无脑点击next安装即可。
安装完成后回到桌面点击右键可以看到Git Baere Here。
点击Git Bash Here,进入Git命令界面,输入命令:
git --version 能正确显示git版本信息,说明就已经安装成功了。
HEC-RAS能够在2D水流区域内添加水工结构。可通过使用SA/2DAreaConn工具在2D水流区内建立一个水工结构。水工结构类似于HEC-RAS中break line,用户可以沿着该水工结构线划分网格,并控制网格单元的大小。见图1。 模型交流,互助+微 xhd825
图1 2D流动区域内的水工结构示例 模型交流视频教程+微 [ xhd825]
SA/2D水力连接可用于模拟二维流动区域内的各种结构。越过结构顶部的流动可以用Weir Equation或Normal 2D Equation Domain来建模。此外,还可以选择为独立的出口添加闸门、涵洞、额定值曲线和流量的时间序列。这些出口类型的任何组合都可以被使用。此外,用户现在可以为每个水工结构出口(涵洞、闸门、额定值曲线和时间序列出口)的上游和下游端部指定X和Y的地理空间坐标。
要在二维流动区域内添加水工结构,请执行以下操作:
1.首先,选择标记为SA/2DAreaConn的几何数据编辑器顶部的绘图工具。然后直接在水工结构的中心画一条线(注意:这条线必须由左岸划到右岸,程序依据此来识别上游侧和背水侧)。这条线将代表水力结构,用于连接一侧的二维流动区域单元到另一侧的结构。该界面将要求定义水工结构的名称。这种结构的中心线也可以在HEC-RAS Mapper中绘制。
2.接下来,修改二维流区域网格,使网格单元沿水工结构线两侧分布。可左键单击水工结构中心线,并选择Edit Internal Connection (Break Line) Cell Spacing选项。在之后弹出的窗口输入网格单元最小和最大间距。默认情况下,它将沿着水力结构中心线使用单元间距的标称单元尺寸,但用户可以改变沿着结构的单元间距,以获得沿着水力结构的更多细节。这一步是可选择的,一般来说,沿着结构中心线建立具有适当大小网格单元是一个好主意。接下来,左键单击水工结构中心线,并在二维流动区域中选择Enforce Internal Connection as Break Line in 2D Flow Area选项。单击此选项后,软件将使用根据结构中心线和单元间距信息来沿着结构的中心线创建沿中心线的网格单元。这是正确划分2D网格来加入水工结构数据(位置-高程数据;涵洞、闸门、缺口等)的必要步骤。
例如,如图3-43所示,在2D流动区域内一堤坝被建模为一个水工结构。2D流区网格单元被修改,使堤坝两侧的网格排列在堤坝的顶部。这需要沿着水工结构中心线增加足够小的单元间距,以获得更好的局部信息。可能你不希望这些网格太小,因为这可能会导致一些网格沿着堤坝分布,这样会使得这部分网格高程与下游相邻网格高程差距过大,当水流超过堤坝时,堤坝背面高程较大细胞可能会导致模型出现稳定性问题。所以,使网格大一点,以包围堤岸斜坡和部分远离堤底区域。
3.接下来,选择几何数据编辑器左侧面板上的 Storage Area/ 2D flow area Hydraulic Connection (SA/2D Area Conn)编辑器。这将打开图2中所示的编辑器。
图2 使用 SA/2D Area Conn将水力结构置于2D流动区域内的例子
用户可以使用 Weir/Embankment Editor编辑器为与自然地面相同或更高的结构定义高程数据。此外,还可以在水工结构中增加涵洞、闸门开口、额定值曲线和时间序列出口过程。用户进入的堰线(位置—高程数据)、涵洞和闸门开口不允许低于它们所连接网格单元最低高程。然而,缺口最小高程也可能比它所连接的网格单元要低(当这样设置时,会得到一个警告信息)。如果缺口也低于它所连接的单元,HEC-RAS 将在缺口侵蚀到地面高程以下时自动动态降低网格高度(上游和下游)。然而,它只会降低两侧结构中心线旁边的单元。
编辑器显示的黑线表示内部水力结构两侧网格的最小高程。这些线向用户展示了水工结构如何连接到结构两侧二维单元的高程和位置。用户可以点击其中任意一条线,获取连接的网格号码,以及单元格的位置(沿水工结构的位置)和高程。此外,该网格将在几何数据编辑器上突出显示,并可看到该网格在空间上的位置。
用户可以选择漫过结构顶部(溢出计算方法)是由 Weir Equation计算还是由 Normal 2D Equation Domain计算。如果选择 Weir Equation,则使用堰方程计算水力结构顶部的所有流量。如果选择 Normal 2D Equation Domain,则将结构顶部的流量计算为网格之间的正常二维流量。在任何一种情况下,通过涵洞和闸门的流量都要分别计算出来,并连接在涵洞或闸门两侧的单元之间。对于高度淹没的结构,其流量不像堰流,二维方程通常会得到更好的结果,但二维方程不适合传统的堰流。
注意:如果结构高度很高,则不应使用Normal 2D Equation Domain选项,这样流过结构的水就会进入自由落体(就像瀑布一样)。对于自由落体情况,Normal 2D Equation Domain不能求解。对于这种情况,用户需要使用 Weir Equation选项。HEC-RAS软件开发者计划研究让程序根据流量条件在Weir Equation和Normal 2D Equation Domain之间自动切换(当前未实现)。
解决vue-cli打包后html文件引用其他文件失效,打开空白问题 写一篇解决问题的博客,最近打包vue项目的时候总是机械性解决bug,出现各种各样可能的问题,看网络上也少有对应的解决方法,所以打算写一个下来。
首先要说明的问题应该就是出现最多的bug,当你写完vue项目的时候,(使用到vue-cli的时候哈),执行run npm build,然后发现打包后的html文件,打开后是空白的,然后按F12键查看控制台输出,出现类似如下的页面:
首先,分析以上报错,共两种,一种是js引用不到,一种是css文件引用不到,而且报错都在产出的index.html文件中报错,这才导致出现空白页面的情况,所以解决这个文件的索引,应该就可以了,而写过原生html的小伙伴知道,我们的html文件引用文件通常如果文件存在,就一定是可以索引到的,那么要做的就是观察html文件的代码及引用的文件是否存在:
<!doctype html> <html lang=""> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1"> <link rel="icon" href="/favicon.ico"> <title>database</title> <script defer="defer" src="/js/chunk-vendors.a61c6f87.js"></script> <script defer="defer" src="/js/app.dd10a5af.js"></script> <link href="/css/chunk-vendors.10dd4e95.css" rel="stylesheet"> <link href="/css/app.346d652b.css" rel="stylesheet"> </head> <body><noscript><strong>We're sorry but database doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript> <div id="app"></div> </body> </html> 以上是打包后的index.html页面,文件的引用位置如上所示,那应该在该页面的根目录中查找对应的文件:
打开js文件:
显然,文件存在,但是为什么找不到呢?
再仔细观察一下报错的部分,就会发现请求的地方是:
GET file:///E:/js/chunk-vendors.a61c6f87.js net::ERR_FILE_NOT_FOUND
E盘下哪里会有这个文件夹,所以归根到最后就是请求的地方出错,我找很久的解决方法,最终锁定在路由模块,当路由开启history模式下,如果没有后端来帮助你获取真正请求的路径时,由于初始页面是没有东西的,或者说是初始页面都是引用到其他组件的部分,但是组件最后被打包到js中,而页面加载一开始就会主动去使用路由,来请求对应的js文件,history模式下如果没有后端主动返回地址,那么就会使用初始URL,自然就是向盘符发送请求了,所以解决这个问题的方法就是将history模式去掉:
在vue的route的index.js中:
import Vue from 'vue' import VueRouter from 'vue-router' Vue.
SqlServer 批量删除表 有某些情境下,我们需要清空包含某些关键字的表(如临时表)或备份表时,就需要执行批量删除的语句。 SELECT row_number()over(order by Name) as FID,Name into #temp FROM SysObjects Where XType='U' --类型,U为实体表 and name like 'TMP%' --表名过滤(自定义就好) ORDER BY Name declare @count int = 0 --行数 declare @i int = 1 --循环所用到的索引 declare @tableName varchar(50) = 0 --表名称 select @count=count(1) from #temp --写入行数值 --开始循环 while(@i <= @count) begin select @tableName=Name from #temp where FID=@i exec('drop table '+@tableName+'') --删除表 select @i=@i+1 --索引+1 end drop table #temp
步骤 1:安装OpenConnect 确保你的系统已经安装了OpenConnect。你可以使用以下命令来安装:
sudo apt-get update sudo apt-get install openconnect 步骤 2:建立SSL VPN连接 使用以下命令连接到远程VPN网关:
sudo openconnect --juniper X.X.X.X:XXX 这个命令中:
--juniper 表示使用Juniper/Pulse Connect Secure模式。X.X.X.X 是远程VPN网关地址。XXX 是远程VPN网关的端口。 在执行该命令后,系统可能会提示你输入用户名和密码,输入正确的凭据后,它应该会建立SSL VPN连接。
步骤 3:断开连接 要断开连接,只需按 Ctrl + C 组合键。
注意事项: 请确保你有权限连接到远程VPN网关,并拥有有效的用户名和密码。
如果远程VPN网关使用自签名证书,可能需要使用 --no-cert-check 选项来忽略证书验证。请注意,这会降低安全性。
你可能需要使用 sudo 权限执行openconnect命令,以便正确建立VPN连接。
如果你的公司或组织提供了特定的VPN客户端,请优先使用它,以确保与网络设备的兼容性。
最近在项目中需要使用到dsPIC33FJ16GS502这款芯片,第一次接触,简单记录一下
软件安装之前建议先把安全软件都先退掉
安装MPLAB-X-IDE开发集成环境(根据安装的环境下载不同的开发环境)
官网下载路径:
https://www.microchip.com/en-us/tools-resources/develop/mplab-x-ide#tabs
安装到这里建议都选上,其余安装步骤默认就行
安装C编译器(根据选型的芯片位数安装相对应的编译器)
官网下载路径:
https://www.microchip.com/en-us/tools-resources/develop/mplab-xc-compilers/
安装到这里建议都选上,其余安装步骤默认就行
安装完成上面两个环境后建议导入一个demo工程编译试试,能正常编译就安装OK
导入工程:
打开MPLAB-X-IDE软件
选择file->open project 选择一个工程打开
点击build编译,出现build successful就是编译通过
安装PICkit 3上位机烧录工具
下载路径(感谢网友分享):
https://download.csdn.net/download/caleb0803/10826507?spm=1001.2101.3001.6650.10&utm_medium=distribute.pc_relevant.none-task-download-2%7Edefault%7ECTRLIST%7Edefault-10-10826507-blog-109575697.235%5Ev38%5Epc_relevant_anti_t3_base&depth_1-utm_source=distribute.pc_relevant.none-task-download-2%7Edefault%7ECTRLIST%7Edefault-10-10826507-blog-109575697.235%5Ev38%5Epc_relevant_anti_t3_base&utm_relevant_index=15
安装路径建议3个环境都装在一个路径下
打开PICkit 3是这样的
安装默认是处于脱机烧录,连上板子后在Device会显示芯片型号,导入hex文件后会自动校验
如果需要使用在线调试,需要点击Tool->Revert to MPLAB mode
之后如果又需要切换回脱机烧录,需要点击Tool->Download PICkit Operating system导入软件安装路径下的hex文件刷一遍默认配置
1. vue3计算属性以及赋值 <template> <!-- 计算属性比如分页器就会使用到 --> <h1>计算属性</h1> <!-- 此时obj.hobby.length是大于0的,所以页面的list为yes --> <h3>{{ list }}</h3> <button @click="getList">获取list的值 ==>{{ val }}</button> </template> <script setup> import {ref, reactive, computed } from "vue"; // 定义变量obj和val const obj = reactive({ todo: '吃饭', hobby: ['打篮球', '打乒乓球', '踢足球'] }) // 定义等下需要将list.value赋值给他的变量 const val = ref(null) // 我们想根据 obj 是否已有一些爱好来展示不同的信息: // 那么我们就使用计算属性 const list = computed(() => { // 用return返回后,list就可以直接使用 // 使用三元表达式来返回yes或者no,此时obj.hobby.length是大于0的,所以页面的list为yes return obj.hobby.length > 0 ? "yes" : 'no' }) // 当然获取的时候同样也是用.
vue3+pinia存储对象赋值踩坑 自我记录
前文描述:大概就是我在本地存储里面的对象obj1 里面的属性名 和我页面赋值 obj的属性名一致,我就直接赋值了,而没有一一对应去赋值,此时出现一个bug,就是因为我obj的对象是v-model双向数据绑定的input值,当我第一次改完触发保存存储时,下次在进入这个页面,先判断如果obj存在就赋值,问题来了,赋值之后我改input,本地存储的数据也变了
大概就是下面这样
// 例如 obj是 const salaryForm = ref({ base: 0, deduct: 0, merit: 0, other: 0, subsidy: 0, }) // obj1是 const salaryInfo = ref() const setSalaryInfo = (v) => { salaryInfo.value = v } // 给obj1赋值 addInfoStore.setSalaryInfo(salaryForm.value) // 页面回显的时候 if(addInfoStore.salaryInfo){ salaryForm.value = addInfoStore.salaryInfo // 错误写法 } // 正确写法 if(addInfoStore.salaryInfo){ salaryForm.value.base = addInfoStore.salaryInfo.base salaryForm.value.deduct = addInfoStore.salaryInfo.deduct salaryForm.value.subsidy = addInfoStore.salaryInfo.subsidy salaryForm.value.merit = addInfoStore.salaryInfo.merit salaryForm.value.other = addInfoStore.