-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.json
1 lines (1 loc) · 37.3 KB
/
index.json
1
[{"content":"Gradle官网地址:Gradle Build Tool\nGradle官方下载安装教程页面:https://gradle.org/install/\nGradle官方用户手册:https://docs.gradle.org/current/userguide/userguide.html\n1. Gradle 入门 1.1 简介 Gradle是一款Google推出的,基于JVM,通用灵活的项目构建工具,支持Maven、JCenter多种第三方仓库;支持传递性依赖管理,废弃了繁杂的xml文件,转而使用简洁的、支持多种语言(Java、Groovy)的build脚本文件。\n常见的构建工具\nAnt:2000年Apache推出的存Java编写构建工具,通过xml[build.xml]文件管理项目。\n优点:使用灵活,速度快(快于Gradle和Maven) 缺点:Ant没有强加任何编码约定的项目目录结构,开发人员需要编写繁杂的xml文件构建指令。 Maven:2004年Apache组织推出的再次使用xml文件[pom.xml]管理项目的构建工具\n优点:遵循一套约定大于配置的项目目录结构,使用统一的GAV坐标进行依赖管理,侧重于包管理。 缺点:项目构建过程过于僵硬,配置文件编写不够灵活,不方便自定义组件,构建速度慢于Gradle Gradle:2012年Goole推出的基于Groovy语言的全新项目构建工具,集合了Ant和Maven各自的优势。\n优点:集Ant脚本的灵活性+Maven约定大于配置的项目目录优势,支持多种远程仓库和插件,侧重于大项目构建。\n缺点:学习成本高、资料少、脚本灵活、版本兼容性等。\n1.2 Gradle 安装 1.2.1 安装JDK 不逼逼,是个人都会。当然,要求JDK版本在1.8及其以上\n1.2.2 下载Gradle Gradle | Releases\n1.2.3 配置环境变量 在系统变量中添加如下两个变量\nGRADLE_HOME:就和JDK配置一样 GRADLE_USER_HOME: 相当于配置Gradle 本地仓库位置和 Gradle Wrapper 缓存目录 然后将GRADLE_HOME 环境变量,添加到Path:%GRADLE_HOME%\\bin\n1.2.4 验证 gradle -v或者gradle --version\n1.3 Gradle 目录结构 Gradle项目默认的目录结构,和Maven项目的目录结构一致,都是基于约定大于配置\nTips:\n只有 war 工程才有 webapp 目录,对于普通的 jar 工程并没有 webapp 目录 gradlew 与 gradlew.bat 执行的指定 wrapper 版本中的 gradle 指令,不是本地安装的 gradle 指令 1.4 Gradle 常用命令 命令 作用 gradle clean 清空编译出来的.build目录 gradle classes 编译src\\main\\java目录下的代码和配置文件 gradle test 编译测试代码,生成测试报告 gradle build 构建项目,该指令也相当于执行了gradle classes跟gradle test gradle build -x test 跳过测试构建项目 需要注意的是:gradle 的命令需要在含有build.gradle的目录中执行\n1.5 修改Maven下载源 Gradle 自带的Maven 源地址是国外的,该Maven 源在国内的访问速度是很慢的,除非使用了特别的手段。一般情况下,我们建议使用国内的第三方开放的Maven 源或企业内部自建Maven 源。\n我们需要在gradle的init.d目录下,创建以.gradle结尾的文件,.gradle文件可以实现在 build 开始之前执行。所以我们可以在这个文件中配置预先加载的操作。\n在init.d目录下创建init.gradle文件(不一定非要叫init,只要以.gradle结尾就行)\nallprojects { repositories { mavenLocal() maven { name \u0026#34;Alibaba\u0026#34; ; url \u0026#34;https://maven.aliyun.com/repository/public\u0026#34; } maven { name \u0026#34;Bstek\u0026#34; ; url \u0026#34;https://nexus.bsdn.org/content/groups/public/\u0026#34; } mavenCentral() } buildscript { repositories { maven { name \u0026#34;Alibaba\u0026#34; ; url \u0026#39;https://maven.aliyun.com/repository/public\u0026#39; } maven { name \u0026#34;Bstek\u0026#34; ; url \u0026#39;https://nexus.bsdn.org/content/groups/public/\u0026#39; } maven { name \u0026#34;M2\u0026#34; ; url \u0026#39;https://plugins.gradle.org/m2/\u0026#39; } } } } 配置概述\nmavenLocal():从本地的maven仓库加载依赖,它找maven本地仓库的顺序是先去USER_HOME/.m2/settrings.xml中找本地maven仓库地址,如果没有则去M2_HOME这个环境变量下的conf/settings.xml中找本地maven仓库地址,如果还没有则认为USER_HOME/.m2/repository这个目录是maven的本地仓库。所以我们可以直接在环境变量中配置M2_HOME=D:\\Install\\maven\\apache-maven-3.6.3来指定maven的地址 mavenCentral():这是代表,如果上面的仓库都无法下载到依赖则从中央仓库下载 但是下载下来的依赖并不是存储在本地maven仓库中,而是放在gradle自己的缓存目录中,默认在USER_HOME/.gradle/caches目录,当然我们之前配置过GRADLE_USER_HOME这个环境变量,所以它就会放在该环境变量下的caches目录中。准确的说gradle并没有本地仓库,他只有caches本地缓存\n2. Wrapper 包装器 Gradle Wrapper 实际上就是对 Gradle 的一层包装,用于解决实际开发中可能会遇到不同项目需要不同版本Gradle的问题。\n例如:我把自己的代码发给别人的时候,会出现如下情况\n对方电脑没有装Gradle 对方电脑Gradle版本太旧无法使用 这时就需要我们使用 Gradle Wrapper ,实际上有了Gradle Wrapper之后,我们本地是可以不安装Gradle的,可以使用Gradle项目自带的Wrapper操作也是可以的。\n而本机电脑安装的Gradle,和项目自带的Gradle Wrapper中Gradle的版本可能不一样,这个很好理解,比如你电脑上装的是8.1.1,别人发给你项目Wrapper中的版本是8.2.1\n查看 Wrapper 的Gradle版本\n我们可以使用gradlew -v或者gradlew.bat -v命令查看Wrapper中的版本\n查看本地Gradle版本\n可以发现版本并不一致,所以当我们想要把项目发给别人或者统一使用的时候,可以将Wrapper中的版本进行修改和开发环境一致\n我们可以通过命令来修改Wrapper的版本号 gradle wrapper --gradle-version=8.1.1\n修改后可以发现Wrapper包中配置文件里的版本就变了\n但此时只是变更了版本信息,并没有真正下载,我们需要通过gradlew -v或gradlew.bat -v命令去查看版本,他会自动下载\n此时我们就可以通过gradlew或者gradlew.bat来执行Gradle相关的指令,操作和Gradle普通指令相同,如下举例:\n3. Gradle 依赖 3.1 快速使用 我们需要在build.gradle文件中导入依赖\nMaven中央仓库地址:https://mvnrepository.com/\n比如我们现在需要导入一个FastJson的依赖\n然后向使用maven一样刷新一下他就会自动下载。\n下载到的gradle地址为:GRADLE_USER_HOME\\caches\\modules-2\\files-2.1\n但按照我们之前 1.5 修改Maven下载源 中的配置,是先去maven仓库中下载,如果maven中已存在的话则不会下载到gradle的这个缓存中\n3.2 Gradle 依赖类型 Gradle提供了三种不同类型的依赖:\nimplementation类型的依赖\nimplementation表示该依赖只在当前 module 中有效,而不会传递给其他依赖它的 module。如果没有指定依赖类型,则默认使用implementation。\n示例代码:\ndependencies { implementation \u0026#39;com.google.code.gson:gson:2.8.6\u0026#39; } api类型的依赖\napi类型的依赖将会传递给其他依赖它的 module,以便于其他 module 中的代码可以使用这些依赖相关的 API。该类型的依赖在模块或库的 API 保持稳定,适合 ThirdParty 使用的时候建议使用。\ndependencies { api \u0026#39;com.google.code.gson:gson:2.8.6\u0026#39; } compileOnly类型的依赖\ncompileOnly只在编译阶段有用,而不会在最终的打包结果中出现。这种依赖在你的代码中仅用于编译检查,但不会在运行时加载。可以使用这种依赖类型来解决在模块中引用其他模块造成的多余依赖版本问题。\ndependencies { compileOnly \u0026#39;junit:junit:4.13.1\u0026#39; } 3.3 依赖的版本规则 Gradle支持使用多种方法指定依赖的版本。下面列举一些实用的版本规则:\n固定版本号\n比如这种写法,完全指定使用的版本号\ndependencies { implementation \u0026#39;junit:junit:4.13.1\u0026#39; } 动态版本号\n有时,我们可能想要使用最新的库版本。Gradle支持使用通配符 * 来指定最新的版本号。例如:\ndependencies { implementation \u0026#39;junit:junit:4.13.*\u0026#39; } 区间版本号\n当我们想要使用一系列版本号时,可以使用开区间或闭区间。例如:\ndependencies { implementation \u0026#39;junit:junit:[4.12, 4.13.1]\u0026#39; } 3.4 排除依赖 如果你添加的一个依赖包含其他不需要的依赖项,Gradle允许你排除这些不需要的依赖项。下面是一个带有不必要依赖项的依赖的示例代码:\ndependencies { implementation \u0026#39;com.example:foo:1.0.0\u0026#39; { exclude group: \u0026#39;org.unwanted\u0026#39;, module: \u0026#39;unwanted-module\u0026#39; } } 在这个示例中,Gradle会自动获取组com.example中的foo以及其所有依赖的库,但会排除org.unwanted组中的unwanted-module库。这可以有效避免依赖冲突和不必要的jar重复引用。\n3.5 依赖本地资源 Gradle还支持使用本地文件系统中的库作为依赖项。通过在dependencies声明中添加本地路径,您可以将本地库添加为项目的依赖项。\n例如,下面的依赖项将模块添加为本地依赖项:\ndependencies { implementation files(\u0026#39;libs/local-library.jar\u0026#39;) } ","permalink":"https://eayonlee.com/tech/java/gradle/gradle%E5%85%A5%E9%97%A8/","summary":"Gradle官网地址:Gradle Build Tool Gradle官方下载安装教程页面:https://gradle.org/install/ Gradle官方用户手册:https://docs.gradle.org/current/userguide/userguide.html 1. Gradle 入门 1.1 简介 G","title":"Gradle入门"},{"content":"一、设置Keepalive 二、设置HTTP Server Stop after 默认情况是360秒吧应该,然后这里个人版本是无法修改的,需要进行破解后才行。\n可以看我另一篇文章 《MobaXterm破解》 进行破解后再做修改。\n","permalink":"https://eayonlee.com/tech/linux/mobaxterm/mobaxterm%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%9E%E6%8E%A5%E6%96%AD%E5%BC%80%E9%97%AE%E9%A2%98/","summary":"一、设置Keepalive 二、设置HTTP Server Stop after 默认情况是360秒吧应该,然后这里个人版本是无法修改的,需要进行破解后才行。 可以看我另一篇文章 《MobaXterm破解》 进行破解后再做修改。","title":"MobaXterm服务器连接断开问题"},{"content":"主要流程就是通过一个Python脚本生成Custom.mxtpro文件,然后放到 MobaXterm 安装目录下接着重启即可\nPython脚本:MobaXterm-Keygen.py\n#/usr/bin/env python3 \u0026#39;\u0026#39;\u0026#39; Author: Eayon License: GPLv3 \u0026#39;\u0026#39;\u0026#39; import os, sys, zipfile VariantBase64Table = \u0026#39;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\u0026#39; VariantBase64Dict = { i : VariantBase64Table[i] for i in range(len(VariantBase64Table)) } VariantBase64ReverseDict = { VariantBase64Table[i] : i for i in range(len(VariantBase64Table)) } def VariantBase64Encode(bs : bytes): result = b\u0026#39;\u0026#39; blocks_count, left_bytes = divmod(len(bs), 3) for i in range(blocks_count): coding_int = int.from_bytes(bs[3 * i:3 * i + 3], \u0026#39;little\u0026#39;) block = VariantBase64Dict[coding_int \u0026amp; 0x3f] block += VariantBase64Dict[(coding_int \u0026gt;\u0026gt; 6) \u0026amp; 0x3f] block += VariantBase64Dict[(coding_int \u0026gt;\u0026gt; 12) \u0026amp; 0x3f] block += VariantBase64Dict[(coding_int \u0026gt;\u0026gt; 18) \u0026amp; 0x3f] result += block.encode() if left_bytes == 0: return result elif left_bytes == 1: coding_int = int.from_bytes(bs[3 * blocks_count:], \u0026#39;little\u0026#39;) block = VariantBase64Dict[coding_int \u0026amp; 0x3f] block += VariantBase64Dict[(coding_int \u0026gt;\u0026gt; 6) \u0026amp; 0x3f] result += block.encode() return result else: coding_int = int.from_bytes(bs[3 * blocks_count:], \u0026#39;little\u0026#39;) block = VariantBase64Dict[coding_int \u0026amp; 0x3f] block += VariantBase64Dict[(coding_int \u0026gt;\u0026gt; 6) \u0026amp; 0x3f] block += VariantBase64Dict[(coding_int \u0026gt;\u0026gt; 12) \u0026amp; 0x3f] result += block.encode() return result def VariantBase64Decode(s : str): result = b\u0026#39;\u0026#39; blocks_count, left_bytes = divmod(len(s), 4) for i in range(blocks_count): block = VariantBase64ReverseDict[s[4 * i]] block += VariantBase64ReverseDict[s[4 * i + 1]] \u0026lt;\u0026lt; 6 block += VariantBase64ReverseDict[s[4 * i + 2]] \u0026lt;\u0026lt; 12 block += VariantBase64ReverseDict[s[4 * i + 3]] \u0026lt;\u0026lt; 18 result += block.to_bytes(3, \u0026#39;little\u0026#39;) if left_bytes == 0: return result elif left_bytes == 2: block = VariantBase64ReverseDict[s[4 * blocks_count]] block += VariantBase64ReverseDict[s[4 * blocks_count + 1]] \u0026lt;\u0026lt; 6 result += block.to_bytes(1, \u0026#39;little\u0026#39;) return result elif left_bytes == 3: block = VariantBase64ReverseDict[s[4 * blocks_count]] block += VariantBase64ReverseDict[s[4 * blocks_count + 1]] \u0026lt;\u0026lt; 6 block += VariantBase64ReverseDict[s[4 * blocks_count + 2]] \u0026lt;\u0026lt; 12 result += block.to_bytes(2, \u0026#39;little\u0026#39;) return result else: raise ValueError(\u0026#39;Invalid encoding.\u0026#39;) def EncryptBytes(key : int, bs : bytes): result = bytearray() for i in range(len(bs)): result.append(bs[i] ^ ((key \u0026gt;\u0026gt; 8) \u0026amp; 0xff)) key = result[-1] \u0026amp; key | 0x482D return bytes(result) def DecryptBytes(key : int, bs : bytes): result = bytearray() for i in range(len(bs)): result.append(bs[i] ^ ((key \u0026gt;\u0026gt; 8) \u0026amp; 0xff)) key = bs[i] \u0026amp; key | 0x482D return bytes(result) class LicenseType: Professional = 1 Educational = 3 Persional = 4 def GenerateLicense(Type : LicenseType, Count : int, UserName : str, MajorVersion : int, MinorVersion): assert(Count \u0026gt;= 0) LicenseString = \u0026#39;%d#%s|%d%d#%d#%d3%d6%d#%d#%d#%d#\u0026#39; % (Type, UserName, MajorVersion, MinorVersion, Count, MajorVersion, MinorVersion, MinorVersion, 0, # Unknown 0, # No Games flag. 0 means \u0026#34;NoGames = false\u0026#34;. But it does not work. 0) # No Plugins flag. 0 means \u0026#34;NoPlugins = false\u0026#34;. But it does not work. EncodedLicenseString = VariantBase64Encode(EncryptBytes(0x787, LicenseString.encode())).decode() with zipfile.ZipFile(\u0026#39;Custom.mxtpro\u0026#39;, \u0026#39;w\u0026#39;) as f: f.writestr(\u0026#39;Pro.key\u0026#39;, data = EncodedLicenseString) def help(): print(\u0026#39;Usage:\u0026#39;) print(\u0026#39; MobaXterm-Keygen.py \u0026lt;UserName\u0026gt; \u0026lt;Version\u0026gt;\u0026#39;) print() print(\u0026#39; \u0026lt;UserName\u0026gt;: The Name licensed to\u0026#39;) print(\u0026#39; \u0026lt;Version\u0026gt;: The Version of MobaXterm\u0026#39;) print(\u0026#39; Example: 23.0\u0026#39;) print() if __name__ == \u0026#39;__main__\u0026#39;: if len(sys.argv) != 3: help() exit(0) else: MajorVersion, MinorVersion = sys.argv[2].split(\u0026#39;.\u0026#39;)[0:2] MajorVersion = int(MajorVersion) MinorVersion = int(MinorVersion) GenerateLicense(LicenseType.Professional, 1, sys.argv[1], MajorVersion, MinorVersion) print(\u0026#39;[*] Success!\u0026#39;) print(\u0026#39;[*] File generated: %s\u0026#39; % os.path.join(os.getcwd(), \u0026#39;Custom.mxtpro\u0026#39;)) print(\u0026#39;[*] Please move or copy the newly-generated file to MobaXterm\\\u0026#39;s installation path.\u0026#39;) print() else: print(\u0026#39;[*] ERROR: Please run this script directly\u0026#39;) 执行该脚本\n# 执行格式 python MobaXterm-Keygen.py \u0026lt;your user name\u0026gt; \u0026lt;your MobaXterm version\u0026gt; # 比如我的用户名是 EayonLee,版本是23.0,则完整命令如下 python MobaXterm-Keygen.py \u0026#34;EayonLee\u0026#34; 23.0 # 如果不知道你的版本是多少可进入MObaXterm后在顶部导航找到Help并点击就能看到版本 执行完脚本后会生成一个Custom.mxtpro文件,然后放到 MobaXterm 安装目录下接着重启即可\n","permalink":"https://eayonlee.com/tech/linux/mobaxterm/mobaxterm%E7%A0%B4%E8%A7%A3/","summary":"主要流程就是通过一个Python脚本生成Custom.mxtpro文件,然后放到 MobaXterm 安装目录下接着重启即可 Python脚本:MobaXterm-Keygen.py #/usr/bin/env python3 \u0026#39;\u0026#39;\u0026#39; Author: Eayon License: GPLv3 \u0026#39;\u0026#39;\u0026#39; import os, sys, zipfile VariantBase64Table = \u0026#39;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\u0026#39; VariantBase64Dict = { i : VariantBase64Table[i] for i in range(len(VariantBase64Table)) } VariantBase64ReverseDict = { VariantBase64Table[i] : i for i in range(len(VariantBase64Table)) } def VariantBase64Encode(bs : bytes): result = b\u0026#39;\u0026#39; blocks_count, left_bytes = divmod(len(bs), 3) for i in range(blocks_count): coding_int = int.from_bytes(bs[3 * i:3 * i","title":"MobaXterm破解"},{"content":"前言 随着我们日常生活工作中需要再电脑上存储的数据量不断增多。如一个3A大作,上百G都不足为奇,蓝光4K超清资源,一部也有70/80G。存储空间不够了怎么办?买硬盘。OK!硬盘到手了,但每个硬盘各有一个分区,七八个盘符看着就闹心。比较重要的数据,想要保险点,还要手动备份到另一块硬盘。如何能够充分利用,多硬盘的优势呢?那就不得不提下磁盘阵列(RAID),一起来了解下~\n1、什么是 RAID RAID(Redundant Array of Independent Disks,独立磁盘冗余阵列)\n其主要核心是把多块独立的磁盘,组成成一个容量巨大的磁盘组,且通过冗余存储提高容错能力。\n2、RAID 物理分类 RAID在物理层面主要分为:软RAID和硬RAID\n2.1、硬RAID 由图可见硬RAID主要有两种方式:\n**阵列柜:**价格较贵,一般用于企业级应用。\n**阵列卡:**价格便宜,适用于普通用户。市面上大部分阵列卡有缓存,可以提升读写速度,且可通过阵列卡中的电池在意外断电的情况下保持缓存中的数据,等供电恢复时再继续写入。\nPS:千万不要尝试使用主板RAID功能,一旦主板要是出现超频失败、电池没电等问题都非常容易导致阵列信息丢失\n硬RAID主要是由专门的RAID控制器来实现RAID功能,且硬RAID通常比软RAID的性能要好,这是因为硬RAID控制器具有专用的处理器和内存,并且不会受到操作系统的负载和其他应用程序的干扰,而软RAID的性能则取决于CPU和操作系统的负载。\n2.2、软RAID 软RAID是通过操作系统和软件来实现RAID功能,它并不想硬RAID的一样有独立的控制器,所以早期的软RAID并不稳定,速度也不及硬RAID,但随着技术不断优化,软硬RAID的差距也就不那么明显了。像大家常见的NAS中通常都是软RAID。\n3、常用 RAID 级别 RAID 是一种通过将多个磁盘组合起来形成一个逻辑硬盘的技术。而且RAID可以分为不同的级别,每个级别具有不同的数据保护和性能特征。\n主要分为标准 RAID(RAID 0 ~ RAID 6)、混合 RAID(JBOD、RAID 7、RAID 10/0、RAID 50 等)\n3.1、RAID 0 RAID0 是一种非常简单的方式,比如我们拿2块磁盘使用RAID0级别。当写入数据时会将一条数据分为不相同的2份,这2份数据会并发的写入到2块磁盘中,相当于每个磁盘存储了一条数据的一半,并不会进行数据的冗余备份,因此读写性能非常高。\n但也正因为它不会对数据校验或冗余备份,因此一旦某块磁盘坏了,数据就直接丢失无法恢复。\nRAID0至少需要两块磁盘,可以使用任意数量的磁盘。每个磁盘的容量不必相同,但是最终的磁盘阵列容量等于最小容量的磁盘乘以磁盘数量。例如:有3块磁盘,分别为500GB、1TB、2TB,那么RAID0的容量为500GB*3=1.5TB\n那有没有可以让存储可靠性变高的方案呢?那就是下面的RAID1\n3.2、RAID 1 RAID1简单理解就是将数据完全备份到另一个磁盘上,也成为镜像。它的有点时可以提高数据的安全性和可靠性,因为每个磁盘都有一份完整的数据副本。如果某个磁盘出现故障,其他硬盘仍然可以正常工作,数据不会丢失。但是缺点就在于降低了存储空间利用率和写入性能,因为每写入一条数据就要无差别的写入到所有磁盘当中。\nRAID1至少需要2块磁盘,可以使用任意偶数数量的磁盘。每个磁盘的容量不必相同,但是最终的磁盘阵列容量等于最小容量的磁盘。例如:如果有4块磁盘,分别为500GB、1TB、2TB和4TB,那么RAID1的磁盘阵列总容量未500GB。\n3.3、RAID5 RAID5因为存储性能、数据安全、存储成本都兼顾,所以是目前使用较多的一种级别。\n在了解RAID5之前,我们可以简单看一下RAID3,虽然RAID3用的很少,但清楚了3就很容易明白5的思路。\nRAID3的方式是:将数据按照RAID0的形式,分成多份然后并发写入多块磁盘,但是还会额外留出一块磁盘用于写奇偶校验码。例如总共有3块磁盘,那么就会让其中2块磁盘来并发的写入数据,第3块磁盘用来记录奇偶校验码。当某块数据盘坏掉时可以通过校验盘对数据进行恢复。\n但由于每写入一条数据都需要去更新校验盘,所以就会导致校验盘的负载较高,也就非常容易损坏。当校验盘损坏了也就无法进行数据恢复了。\nRAID5的方式可以说是对RAID3进行了改进。在RAID5的模式中,不需要单独用一个磁盘记录奇偶校验码,它会把奇偶校验码分布在各个磁盘中。例如,总共有3块磁盘,那么会将要写入的数据分成3份,并发写入3块磁盘中,同时还将数据的奇偶校验码信息也写入到这3块磁盘中(数据对应的校验码必须存储在不同的磁盘上)。一旦某一块磁盘损坏,就可以通过剩下的磁盘中的校验码信息进行数据恢复。\nRAID5校验位算法原理:P = D1 xor D2 xor D3 … xor Dn (D1,D2,D3 … Dn为数据块,P为校验,xor为异或运算)\nRAID5的方式,最少需要三块磁盘来组建磁盘阵列,允许最多同时坏一块磁盘。如果有两块磁盘同时损坏了,那数据就无法恢复了。\nRAID5可以使用任意数量的硬盘。每个硬盘的容量不必相同,但是最终的磁盘阵列容量等于最小容量的硬盘乘以硬盘数量减一。例如,如果有五块硬盘,分别为500GB、1TB、2TB、3TB和4TB,那么RAID5的容量为500GB x (5 - 1) = 2TB。\n3.4、RAID6 为了进一步提高存储的高可用,大佬们又提出了RAID6方案,可以在有两块磁盘同时损坏的情况下,也能保障数据可恢复。\n为什么RAID6这么牛呢,因为RAID6在RAID5的基础上再次改进,引入了双重校验的概念。\nRAID6除了每块磁盘上都有同级数据XOR校验区以外,还有针对每个数据块的XOR校验区,这样的话,相当于每个数据块有两个校验保护措施,因此数据的冗余性更高了。\n但是RAID6的这种设计也带来了很高的复杂度,虽然数据冗余性好,读取的效率也比较高,但是写数据的性能就很差。因此RAID6在实际环境中应用的比较少。\n3.5、RAID10 RAID10是一种将RAID1和RAID0结合起来的方法,也称为镜像条带化(mirrored striping)。\n比如我们现在有4个磁盘,将4个磁盘分为两组(每组2个磁盘),当我们写入一条数据的时候首先会基于RAID0将一条数据分为不相同的2份,这2份数据会并发的写入到2组磁盘中,相当于每组磁盘存储了一条数据的一半。此时再每组磁盘的基础上使用RAID1,将这条数据的一半并发写入到当前磁盘组的所有磁盘中进行冗余备份。\n但也可以看出RAID10模式是有一半的磁盘空间用于存储冗余数据的,浪费的很严重,因此用的也不是很多。\n4、总结 RAID级别 最少磁盘数 容量公式 优点 缺点 RAID0 2 N*S 高速读写 无冗余备份,可靠性低 RAID1 2 S 数据可靠 空间利用率低 RAID5 3 (N - 1) * S 平衡 写性能低 RAID10 4 (N / 2) * S 高速且高可靠 空间利用率低 ","permalink":"https://eayonlee.com/tech/storage/raid%E7%A3%81%E7%9B%98%E9%98%B5%E5%88%97/","summary":"前言 随着我们日常生活工作中需要再电脑上存储的数据量不断增多。如一个3A大作,上百G都不足为奇,蓝光4K超清资源,一部也有70/80G。存储空间不够了怎么办?买硬盘。OK!硬盘到手了,但每个硬盘各有一个分区,七八个盘符看着就闹心。比较重要的数据,想要保险点,还要手动备份到另一块硬盘","title":"RAID磁盘阵列"},{"content":"1 简介 Supervisor是用Python开发的一套通用的进程管理工具,能将一个普通的命令行变为后台Daemon,并监控进程状态,异常退出时能自动重启。是通过 fork/exec 的方式把这些被管理的进程当作Supervisor的子进程来启动,这样只要在Supervisor的配置文件中,把要管理的进程可执行文件的路径写进去即可。\nSupervisor主要分为以下四个核心部分:\nSupervisord:它是Supervisor服务的主要管理器,运行Supervisor时会启动一个进程Supervisord,它负责启动所管理的进程;并将所管理的进程作为自己的子进程来启动,而且可以在所管理的进程出现崩溃时自动重启 Supervisorctl:这是Supervisor服务的客户端命令行工具,可以用来执行stop、start、restart等命令来对这些子进程进行管理 Web Server:这是Supervisor服务的网页可视化界面,可以通过Web界面查看和控制进程状态,简化了对操作命令的学习 xml-rpc interface:服务于Web UI的同一个HTTP服务器,提供一个xml-rpc接口,可以用来查询和控制管理程序及其他运行的程序 官网:www.supervisord.org。\n2 Supervisor服务运行环境说明 Supervisor可以运行在大多数泪Unix系统,但是不能运行在任何Windows系统,Supervisor运行在Python环境中,可以在Python2和Python3版本上工作。\n3 Supervisor 安装 由于我是Ubuntu系统所以这里使用apt的方式,CentOS自行使用yum\n当然你也可以通过安装python-pip,然后通过pip install supervisor来安装Supervisor也是没问题的\n# 安装 sudo apt update \u0026amp;\u0026amp; sudo apt install supervisor # 验证 sudo systemctl status supervisor supervisord -version 4 配置进程管理 Supervisor安装完成之后会在系统中生成两个主要的配置文件:\n主进程配置文件:/etc/supervisor/supervisord.conf\n子进程配置文件目录:/etc/supervisor/conf.d/\n注意:如果你是用pip方式安装的Supervisor,默认是没有主进程和子进程配置文件的,但你可以通过echo_supervisord_conf \u0026gt; /etc/supervisor/supervisord.conf命令生成一个主进程配置文件,然后通过mkdir /etc/supervisor/conf.d生成一个子进程配置文件目录\n4.1 Supervisord 配置及启动 如下为完整的supervisord.conf配置文件\n;开头的代表注释,有可能你默认的配置文件和下面的不一样,你可以按照下面的配置进行相应的增加,如下是4.1.0版本完整配置\n有些路径配置尽量保持你默认配置不要修改\n[unix_http_server] file=/var/run/supervisor.sock ; socket套接字文件的路径,用于客户端和服务端建立本地连接 chmod=0700 ;socket文件的权限,默认是0700 ;chown=nobody:nogroup ;socket文件属主与属组信息设定,格式:uid:gid,注释掉使用默认就行 ;[inet_http_server] ;Web界面配置,默认是没有的(关闭),一般企业里使用也不打开 ;port=127.0.0.1:9901 ;Web管理后台运行的IP和端口,如果开放到公网切部署在云服务器,这里应该是内网ip ;username=user ;登录管理后台的用户名 ;password=123 ;登录管理后台的密码 [supervisord] logfile=/var/log/supervisor/supervisord.log ;主日志文件;默认为$CWD/supervisor.log logfile_maxbytes=50MB ;日志文件大小,超出会rotate,默认50MB,如果设置成0表示不限制大小 logfile_backups=10 ;主日志文件的备份数量,默认是10,设为0表示不备份 loglevel=info ;日志级别,默认为info,其它值为“debug,warn,trace” pidfile=/var/run/supervisord.pid ;supervisord服务进程pid文件,如果没有改文件也就说明supervisord没有运行 nodaemon=false ;是否在前台启动,默认是false,即以daemon(后台)的方式启动 minfds=65536 ;可以打开的文件描述符的最小值,默认 1024,企业中可以调整到最大65536 minprocs=200 ;可以打开的进程数的最小值,默认 200,企业中默认200够用 ;如下全部注释掉,一般也不使用,需要时可按需打开 ;umask=022 ; (process file creation umask;default 022) ;user=chrism ; (default is current user, required if root) ;identifier=supervisor ; (supervisord identifier, default is \u0026#39;supervisor\u0026#39;) ;directory=/tmp ; (default is not to cd during start) ;nocleanup=true ; (don\u0026#39;t clean up tempfiles at start;default false) ;childlogdir=/tmp ; (\u0026#39;AUTO\u0026#39; child log dir, default $TEMP) ;environment=KEY=value ; (key value pairs to add to environment) ;strip_ansi=false ; (strip ansi escape codes in logs; def. false)[supervisorctl] [rpcinterface:supervisor] ;用于外部程序或工具通过rpc接口与 Supervisor 通信和控制被监控的进程。比如supervisorctl,一定要添加,不然supervisorctl用不了 supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface [supervisorctl] serverurl=unix:///var/run/supervisor.sock ; supervisorctl通过socket连接supervisord服务端,路径需要和与unix_http_server中的file一致,该方式也就是通过本地的方式连接 ;如果你想通过网络http的方式可以使用下面的配置,但是下面和上面的serverurl不能共存,切记 ;serverurl=http://127.0.0.1:9001 ;通过HTTP的方式连接supervisord ;username=chris ; should be same as http_username if set ;password=123 ; should be same as http_password if set ;prompt=mysupervisor ; cmd line prompt (default \u0026#34;supervisor\u0026#34;) ;history_file=~/.sc_history ; use readline history if available;[program:xx]是被管理的进程配置参数,xx是进程的名称 [include] files = /etc/supervisor/conf.d/*.ini ;相当于是引入其他的配置文件进来,支持ini和conf,一般program配置我们不会写在当前配置文件中,都会单独写在外面,所以就可以通过include进行引入 修改完配置文件之后先查看是否已启动supervisord,如果启动需要重启加载我们新更新的配置\n# 查看进程 root@bj-ubuntu-eayon:~# ps -ef | grep supervisord root 3463154 1 0 Sep02 ? 00:00:09 /usr/bin/python3 /usr/bin/supervisord -n -c /etc/supervisor/supervisord.conf root 3878074 3876890 0 12:06 pts/0 00:00:00 vim supervisord.conf root 3894307 3893980 0 13:12 pts/2 00:00:00 grep --color=auto supervisord # kill supervisord root@bj-ubuntu-eayon:~# kill -9 3463154 指定supervisord.conf配置文件启动supervisord\nsupervisord -c /etc/supervisor/supervisord.conf 如果出现Unlinking stale socket /var/run/supervisor.sock错误,可以通过sudo rm /var/run/supervisor.sock删除后重试\n启动好之后建议通过ps -ef | grep supervisord查看启动进程,如果出现两个的话讲最旧的进行删除。\n访问Web\n4.2 Program 子进程配置文件 比如我们现在想要通过Supervisor来管理一个Nginx,首先先下载一个Nginx\nsudo apt install nginx # 下载完之后他会默认启动,可以看一下 root@bj-ubuntu-eayon:/opt# systemctl status nginx ● nginx.service - A high performance web server and a reverse proxy server Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled) Active: active (running) since Sun 2023-09-03 14:41:16 CST; 13s ago Docs: man:nginx(8) Main PID: 3936874 (nginx) Tasks: 3 (limit: 2262) Memory: 5.4M CGroup: /system.slice/nginx.service ├─3936874 nginx: master process /usr/sbin/nginx -g daemon on; master_process on; ├─3936875 nginx: worker process └─3936876 nginx: worker process # 那我们先把它给kill掉 root@bj-ubuntu-eayon:/opt# ps -ef | grep nginx root 3936874 1 0 14:41 ? 00:00:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on; www-data 3936875 3936874 0 14:41 ? 00:00:00 nginx: worker process www-data 3936876 3936874 0 14:41 ? 00:00:00 nginx: worker process root 3937378 3893980 0 14:42 pts/2 00:00:00 grep --color=auto nginx root@bj-ubuntu-eayon:/opt# kill -9 3936874 3936875 3936876 Program配置文件就是配置我们要管理的进程的配置文件。当然也可以把下面所有配置项都写到 supervisord.conf 文件里,但并不推荐这样做,而是通过在supervisord.conf中通过include 的方式把不同的程序(组)写到不同的配置文件里。\n由于我们的子进程配置文件目录是/etc/supervisor/conf.d/,所以我们需要在该目录下创建/etc/supervisor/conf.d/nginx.ini\n[program:nginx] ; 当前被管理程序,格式: [program:xxx] 后面的名字可以随意 command=/usr/sbin/nginx -g \u0026#39;daemon off;\u0026#39; ; 程序启动命令,跟手动在命令行启动的命令是一样的 autostart=true ; 当前被管理程序是否随supervisord一起启动 startsecs=10 ; 当前被管理程序启动10秒后没有异常退出,就表示进程正常启动了,默认为1秒,根据具体服务的启动时长进行改变,比如java就比较慢 autorestart=true ; 当前被管理程序退出后自动重启,可选值:[unexpected,true,false],默认为unexpected,表示进程意外杀死后才重启 startretries=1 ; 当前被管理程序启动失败自动重试次数,默认是3 user=root ; 用哪个用户启动当前被管理程序,默认是root priority=999 ; 当前被管理程序启动优先级,默认999,该值最小的优先启动 redirect_stderr=true ; 重定向stderr错误日志到stdout标准日志,默认false,一般都会重定向到一个 stdout_logfile=/var/log/nginx/nginx.log ; 程序运行输出的stdout标准日志文件(正常运行日志),需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录 stdout_logfile_maxbytes=20MB ; stdout 日志文件大小,默认50MB stdout_logfile_backups=20 ; stdout 日志文件备份数,默认是10 ;stderr_logfile=/opt/apache-tomcat-8.5.87/logs/catalina.err ; 程序运行输出的stderr错误日志文件输出路径 ;stderr_logfile_maxbytes=1MB ; stderr 日志文件大小,默认50MB ;stderr_logfile_backups=10 ; stderr 日志文件备份数,默认是10 ;stopasgroup=false ; 默认为false,当前被管理程序被杀死时是否向这个进程组发送stop信号,包括子进程 ;killasgroup=false ; 默认为fakse,当前被管理程序被杀死时是否向这个进程组发送kill信号,包括子进程 切记:配置中的日志输出路径和日志文件一定要提前创建,否则启动失败\n当添加/修改子进程配置之后,可以使用supervisorctl reread进行配置检查,配置无误后通过supervisorctl update更新配置。\n此时在后台就可以直接看见新增的子进程\n5 常用命令介绍 supervisorctl status nginx # nginx状态 supervisorctl stop nginx # 停止nginx supervisorctl start nginx # 启动nginx supervisorctl restart nginx # 重启nginx supervisorctl reoload nginx # 重载nginx supervisorctl update nginx # 配置文件修改后可以使用该命令加载新的配置 # 所有子进程 supervisorctl start all # 启动所有被监控的进程 supervisorctl stop all # 停止所有被监控的进程 supervisorctl restart all # 重启所有被监控的进程 supervisorctl reload all # 重新加载所有被监控的进程的配置 supervisorctl shutdown # 关闭Supervisor # 主要针对supervisord.conf配置文件的刷新,而不需要重启 Supervisor 进程。当修改了supervisord.conf,例如增加或修改了进程配置时,使用 reload 命令可以应用这些更改。重要的是,reload 不会中断已经在运行的进程,只会影响新的配置更改。 supervisorctl reload # 检查supervisord配置和引入的子进程配置文件,如果配置文件没有问题,将显示 xxxxxxx: available supervisorctl reread # 主要针对子进程配置文件的刷新,它关注于管理和操作已定义的进程,而不会重新加载 supervisord.conf 的主配置文件。 supervisorctl update ","permalink":"https://eayonlee.com/tech/linux/supervisor/supervisor%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86%E5%B7%A5%E5%85%B7/","summary":"1 简介 Supervisor是用Python开发的一套通用的进程管理工具,能将一个普通的命令行变为后台Daemon,并监控进程状态,异常退出时能自动重启。是通过 fork/exec 的方式把这些被管理的进程当作Supervisor的子进程来启动,这样只要在Supervisor的配置文件中,把要管理的进","title":"Supervisor进程管理工具"},{"content":" Eayon\u0026#39;s Blog 一个分享技术、阅读、生活的博客 ","permalink":"https://eayonlee.com/links/","summary":"Eayon\u0026#39;s Blog 一个分享技术、阅读、生活的博客","title":"🤝 Links"},{"content":" section .data name db \u0026#34;Eayon Lee\u0026#34;, 0 prefer_name db \u0026#34;Eayon\u0026#34;, 0 born_year dd 1997 hometown db \u0026#34;Suqian, Jiangsu, CN\u0026#34;, 0 curr_location db \u0026#34;Chaoyang, Beijing, CN\u0026#34;, 0 ","permalink":"https://eayonlee.com/about/","summary":"section .data name db \u0026#34;Eayon Lee\u0026#34;, 0 prefer_name db \u0026#34;Eayon\u0026#34;, 0 born_year dd 1997 hometown db \u0026#34;Suqian, Jiangsu, CN\u0026#34;, 0 curr_location db \u0026#34;Chaoyang, Beijing, CN\u0026#34;, 0","title":"🙋🏻♂️ About"}]