不为有趣之事,何遣有涯之生
不失其所者久,死而不亡者寿

AI重塑商业系列(2)

hzqiuxm阅读(82)评论(0)

开篇引子:不是AI做不到,而是你没想到

在AI技术突飞猛进的今天,真正拉开人与人差距的,不再是“你会不会用AI”,而是“你能不能构建AI产品”。

如果说第一波AI浪潮是工具红利,人人可用;那么接下来的核心竞争力,就是谁能把AI融入流程、嵌入产品、重构场景。

但这就引出一个关键问题——AI该用在哪里?又该怎么用?

这正是本篇所聚焦的主题:AI需求的系统化挖掘方法

AI需求挖掘与传统IT产品差别

我们太熟悉传统IT了,熟悉到很多流程、动作已经变成了“无意识能力”——这在心理学中被称为“不知道自己知道”。

这种熟练本来是优势,却会让人在设计AI产品时进入盲区:

“我们总是用旧眼光看新事物”,于是就看不到AI真正能带来的结构性价值。

我们需要的是一套新的思维框架,帮助我们突破习惯的思维路径,重新识别业务中那些看似“理所当然”的脑力环节。

于是,我们引入 MAIR 模型

MAIR:一套用于AI需求挖掘的思维工具

MAIR 是一个横跨业务与技术的四步法,帮助你识别可被AI替代的脑力劳动点

Map Business Processes:梳理流程
Access Mental Labor part:寻找脑力劳动
Identify Value of Mental Tasks:确定脑力价值
Replace with AI Solution:设计替代方案

image.png

M 梳理业务流程

这一步的动作是梳理业务流程,把“思维动作”挖出。

挖掘过程中要做到尽量拆到最小颗粒程度。为了帮助大家拆的尽可能细,这里推荐使用5W工具去拆,一直连续追问五个为什么(杰斐逊纪念堂外墙清洁问题)。

**Why1**‌:为什么纪念堂外墙腐蚀严重?  
→ 清洁人员频繁使用高压水枪+强碱清洁剂冲洗

‌**Why2**‌:为什么需要使用强效清洁剂?  
→ 普通清洁剂无法清除顽固的鸟粪痕迹

‌**Why3**‌:为什么外墙有大量鸟粪?  
→ 燕子群在墙面筑巢栖息

‌**Why4**‌:为什么燕子在此聚集?  
→ 墙缝蜘蛛数量暴增(燕子主要食物)

‌**Why5**‌:为什么蜘蛛异常繁殖?  
→ 夜间灯光吸引趋光昆虫(蜘蛛的食物源)

‌**根本解决方案**‌:调整纪念馆夜间照明方案(减少开灯时间/更换灯光波长),从源头阻断生态链。

这一步拆解的工作其实也是为后续写提示词做好准备,后面借用提示词框架,你需要做的就是对业务规则和流程进行翻译,而不是创造。

A 寻找脑力劳动

完成梳理后,在流程中寻找哪些部分是通过脑力劳动来完成的。

“脑力劳动”并不等同于“所有非体力劳动”。这里特指的是依赖人类经验、理解、创造性或归纳判断的环节

你可以用以下四类关键词来快速定位流程中是否有“脑力成分”:

  • 思考类:推理、分析、筛选、归因
  • 判断类:评分、优先级排序、异常识别
  • 创作类:文案撰写、提案草拟、设计命名
  • 沟通类:客户回复、邮件编写、报告生成

注意区分:

  • 若该任务规则固定、路径明确(例如:填写快递单、审批单流程),更适合 RPA 自动化或低代码平台;

  • 若该任务依赖人脑临场判断、涉及语义或情绪理解,才是 AI 大模型发挥作用的机会点。

I 确定脑力价值

不是所有脑力劳动都值得被 AI 替代。你需要从价值/成本比的角度来评估是否“值得动手”。

我们可以参考两个主要维度:

难度评估(单位时间产出成本)
- 岗位人力成本:是否是高薪岗位?
- 替代难度:是否已有成熟模型能应对?
- AI正确率容忍度:如果偶尔出错,是否能容忍?

时间评估(总时长)
- 该任务在整个流程中耗时占比高吗?
- 是不是高频发生?
- 是否可批量处理?

优先替代的任务画像:人力成本高(如咨询、分析、创作类任务);每天/每周都要做;即使AI生成的结果需要二次校对,但已经节省了80%时间

简化评估模型公式:

替代优先级 = 难度 × 频率 × 人力成本

R 寻找替代方案

最后一步是把已经识别出的“高价值脑力劳动”进行产品化尝试,用大模型、工作流或外部工具初步实现替代。

这个过程可以拆分为三个步骤去做:

  • 确定输出:以终为始,确定 AI 输出物
  • 确定输入:回溯输入信息,确定输入的内容、来源、风格等
  • 构建提示词 + 验证流程:采用熟悉的 Prompt 模板(如 CRISPE、Expert Chain、Role-Based Prompt 等),分段测试大模型表现,逐步逼近目标效果。最好进行“盲测”:将 AI 结果直接嵌入真实流程中,观察是否被识别为“机器生成”。

如果模型效果一般,不急着做系统化产品,可以先作为辅助决策工具;如果模型表现稳定,可考虑用 API 封装,嵌入后台流程中自动调用;如果模型生成部分可用,部分不稳,可结合“人机协作”设计来优化流程效率。

结语

MAIR的理论部分就介绍到这里,下一篇我会举一个具体的例子,完整的进行MAIR的拆解,并输出一个产品demo验证。

AI需求挖掘,不只是找场景,更是重构“人机分工”

MAIR模型不是教我们“怎样用AI做点事情”,而是帮助我们重新梳理人与AI的协作边界:

  • 把人从低效的判断和重复的脑力任务中解放出来,
  • 把AI放进那些“能理解规律、能产生价值”的环节里,
  • 最终构建出更流畅、高效、有智慧感的工作与产品流程。

AI不会自动告诉你它该做什么,真正的产品洞察,依然来源于对业务的熟悉、对流程的敏感、对脑力成本的精算

当我们学会了用结构化方式识别“脑力密集区”,就真正具备了打造AI产品的第一性能力。

AI替代的浪潮不会因为我们的迟疑而停下。

于其问自己“AI能不能替代我”,然后恐慌,不如追问自己:我的思考方式,是不是还有改进和重构的空间?是不是可以借助AI完成同步升级。

AI重塑商业系列(1)

hzqiuxm阅读(181)

引子:为什么是现在?

十年前,当你打开软件,看到的是界面和功能;十年后,当你与软件对话,它看到的是你。

曾经的软件,定义了功能,用户只能去学习和适应它;
今天的AI,理解你的话语、你的习惯、甚至你的潜在需求。

当产品不再局限于界面按钮,而变成了一个能听懂你、理解你、甚至预测你的私人助理,商业的规则也注定要被彻底改写。

我们正处于一个新旧交替的关键时刻,从“功能软件”迈入了“意图驱动”的新世界。
而AI,就是这场商业与产品哲学大变革的核心推手。

AI究竟如何重塑商业世界?我们先回到商业的八大核心要素,来看看AI究竟能带来怎样的转变。

商业八要素的AI升级

大模型时代,我们可以围绕商业核心八要素系统性地实现AI升级。这八个核心要素贯穿了商业活动的全部环节,任何一家企业都离不开它们。

通过收益视角,我们可以探讨每个要素如何利用AI技术降本增效,实现商业转型和价值升级。

  • 定位:通过AI自动分析用户画像与需求数据,降低传统定位调研的人力与资金成本。实时动态调整产品与品牌定位,快速响应市场变化,提升竞争力。

  • 市场:利用AI进行市场趋势预测和精准用户洞察,减少市场调研和分析所需的人工和周期。通过AI洞察与预测,发现新的市场机会与竞争要素,更快进入有潜力的新领域。

  • 产品:AI加持,对老产品提升溢价。创造新产品新增收益,为个性化产品增加利润空间,增加用户粘性和产品竞争力。

  • 营销:进行人力替代,物料成本替代。使用AI智能推荐与自动化内容生成,减少传统营销策划和渠道运营的人工投入。增加物料输出,通过媒体矩阵流程获取。

  • 生产:AI自动化生产流程,完成人力替代,质量控制损耗降低;利用AI提升产能和效率。

  • 决策:利用AI分析海量数据,降低决策错误风险成本;利用AI实时洞察、模拟、预测,提升决策能力,提升投资收益率。

  • 资源:AI优化资源配置,避免冗余与浪费,节约运营成本;AI自动发现资源使用的最佳路径,提高资源的产出效率与利用率。。

  • 管理:AI支持智能化管理,完成部分人工替代,优化内部流程,提升管理覆盖度,提升组织效率。

AI时代的每个商业环节,都在被重新定义,推动企业进入全新发展阶段。

AI重塑产品价值的启示

现有软件应用的特点:有限Input,用户适应产品;站外搜索,多产品切换;处理结构化数据;服务撮合、促进交易;人和人对话;功能迭代;

大模型时代软件应用:无限Input,产品适应用户;贴身助手、辅助驾驶;处理非结构化数据;直接提供服务;人VS机器、机器VS机器;模型迭代;

image.png

我们再看几个具体的例子:

  • 会说话的仙人掌变成FoloToy之后,售价从13元涨到398元,还搭配了语音陪伴服务;

  • 传统地球仪加上AI讲解和问答功能,从10元变为529元,变成了“可以互动的地理老师”;

  • 直播网红与MCN机构,利用AI创造出语音陪聊账号、内容策划助手、AI合成主播,提升效率。

这些商品因为AI而升级,本质上不是打造了全新的产品,而是给原有产品赋予了“灵魂”和“陪伴感”。

AI新产品系统化设计

简单说AI产品构建包含三个核心层次:

  • AI替代层:用AI代替人工操作,直接降低运营成本,比如AI客服。

  • AI增强层:用AI提升产品效果,显著提高业务效率,如智能推荐和精准营销。

  • AI重构层:用AI打造新产品,创造新的市场需求,例如AI伴读、AI编程助手。

那么从商业层面构建一个AI产品,大概可以分为七个步骤。

image.png

  • 1 需求挖掘:解决AI从哪里入手的问题。

  • 2 价值评估:判断这样做值不值的问题。

  • 3 产品构建:解决AI产品设计问题。

  • 4 产品架构:解决AI产品能力和适应问题。

  • 5 产品实施:解决AI产品落地问题。

  • 6 商业策略:解决AI产品赚钱问题。

  • 7 产品迭代:解决AI产品精度和后续提升问题。

因此,AI产品的构建不再凭感觉,而是可以遵循明确的方法论。

之后的文章里,我会对每个步骤进行详细的拆解与举例。这样大家就会有更加清晰的认识,当你工作中碰到某个环节时,只要拿上对应的模型,就能进行有效的思考与分析了。

结语

AI产品的核心变革,不止于技术,更是产品、用户与商业关系的全面重塑:

  • 产品,不再只是工具,而是理解你意图的伙伴;

  • 商业,不再只是买卖关系,而是持续的陪伴与共生。

AI正在赋予商业『生命感』,让商业不仅『更聪明』,更『有人情味』。

未来的竞争,从不是谁的AI更强大,而是谁的AI更懂人心。

你和你的团队,准备好迎接这场『从功能到智能,从交易到共生』的商业革命了吗?

工程师工具箱系列(4)

hzqiuxm阅读(144)

Gemini-cli快速使用教程

image.png

收费丝滑免费也香

说实话,现在有些大模型和工具是真的好用,比如Cursor、GPT-4O等。但是所有付费工具加起来,也是一笔不小的费用。

平时工作、生活中我们遇到的问题,并不一定非得上最好的大模型或最好的工具,有时候稍微次一点的大模型或工具也完全能够胜任了。

所以收费用着确实丝滑,但免费的也香啊。

Google这次推出的Gemini CLI直接解决了这个痛点。你只需要用个人Google账户登录,就能获得免费的Gemini Code Assist许可证,每分钟60次调用,每天1000次调用,完全免费使用Gemini 2.5 Pro的完整版本这个额度对个人开发者来说真的很够用了。

很多小伙伴在使用过程中,还是难免会踩一些坑,这里做个入门使用说明,希望可以帮助到大家。

1 准备阶段

  • 需要一个代理梯子,这个我就不额外说明了,用你自己喜欢的就好

  • 找到自己代理梯子代理端口

2 配置环境

根据自己工作电脑环境进行配置即可

Windows (CMD/PowerShell)‌:

[CMD]
set http_proxy=http://127.0.0.1:你的代理端口 
set https_proxy=http://127.0.0.1:你的代理端口

[PowerShell]
$env:http_proxy="http://127.0.0.1:你的代理端口"  $env:https_proxy="http://127.0.0.1:你的代理端口"
  • macOS/Linux‌:

    export http_proxy=http://127.0.0.1:你的代理端口
    export https_proxy=http://127.0.0.1:你的代理端口

完成后测试下自己命令行下是否可以访问谷歌:curl google.com

3 设置项目编号

本来我以为开通了gemini-cli的API就好,后来测试发现还是必须要设置下项目的ID才行。

访问谷歌控制中心 https://console.cloud.google.com/home/dashboard

image.png

复制项目ID,按照下面命令完成设置:

- CMD: `set GOOGLE_CLOUD_PROJECT=你的项目ID`
- ‌PowerShell‌: `$env:GOOGLE_CLOUD_PROJECT="你的项目ID"`
- ‌macOS/Linux*: `export GOOGLE_CLOUD_PROJECT=你的项目ID`

5 启动gemini-cli

  • 建议使用: npx https://github.com/google-gemini/gemini-cli 来启动

  • 使用全局npm的方式因为大家node环境以及依赖问题,可能会遇到莫名其妙的坑

  • 启动后随便聊个天,有回复说明OK了

image.png

  • 还剩下多少免费额度,你可以通过右下角的百分比来跟踪

image.png

遇到错误

  • 遇到错误不要慌:根据命令gemini -d 或提示,ctrl + o ctrl +s 查看详情
  • 一般应该都是超时,说明代理端口可能设置的不对
  • 使用 curl google.com 在命令行窗口里看看是否能通

自动化脚本

每次都要执行这些命令明显太繁琐了,所以我们需要编写一个脚本,然后下次在任何项目里启动就行。

这里以window为例,linux和mac下就和正常shell脚本类似,不特殊说明了

1.编写脚本

### PowerShell 脚本示例:start-gemini-cli.ps1

# powershell
# 设置 HTTP 和 HTTPS 代理环境变量
$env:http_proxy = "http://127.0.0.1:代理端口"
$env:https_proxy = "http://127.0.0.1:代理端口"

# 设置 GOOGLE_CLOUD_PROJECT 环境变量
$env:GOOGLE_CLOUD_PROJECT = "项目ID"

# 使用 npx 启动 gemini-cli
npx https://github.com/google-gemini/gemini-cli

2.配置环境变量和放开权限

将脚本目录设置到环境变量path中

执行:Set-ExecutionPolicy Unrestricted -Scope CurrentUser

3.执行脚本

start-gemini-cli.ps1

好了,使用说明就到这里,希望对你有所帮助~

对个人而言AI时代机遇是什么?

hzqiuxm阅读(154)

对个人而言AI时代机遇是什么?

是什么构成了AI时代普通人的机遇

image.png

技术一路从蒸汽机,到电动机,到信息互联网,再到人工智能。到现阶段,构成我们普通人的机遇是什么呢?

根据黄金思维圈的法则,要想弄清楚 What 的问题,我们先想清楚 Why。为什么AI时代可以带给普通人机遇?

我认为有三个原因,它们分别是生产力的大幅度提升、广泛的使用场景、参与门槛很低。

生产力大幅度提升

生产力的大幅度提升,是撬动机会的杠杆。

技术革命的每一次进化,本质上都是生产力的飞跃,而每一次飞跃,都会打破一批人的局限,也成就一批人的崛起。

在AI面前,很多传统上需要大量人力的任务变得轻松可行。一人就是一个团队,不再需要写手、画手、剪辑师、翻译……只要你有想法,AI就是你的手脚和羽翼

《荀子·劝学》有言:“不积跬步,无以至千里;不积小流,无以成江海。”而今,我们终于拥有了一条可以迅速流动的小溪,它叫“AI工具”。问题只是:你是否愿意迈出那第一步?

广泛使用场景

场景的广泛应用,是遍地的微型矿脉。

AI的能力广,广到你很难设限:文本、图像、音频、视频、代码、翻译、数据分析、客服辅助……这些看似普通的场景,每一个背后,都藏着细碎但真实的价值。

也正因为场景广泛,AI的产业链也足够长、足够广。
从模型训练、工具开发、平台运营,到客户服务、内容优化、交互设计,整条链路上涌现出无数岗位、无数需求。这就像一张被撒开的大网,捞起的不只是高薪岗位,还有属于普通人的可及机会。

而对于个体而言,这些广泛场景带来了两种真正的核心机遇

  • 一是直接进入新兴行业。AI工具本身就是一门手艺,内容生成、AI运营、AIGC顾问、提示工程师……都是这几年才诞生的新岗位;

  • 二是成为传统行业的技术转型推动者。你不需要离开原本的领域,但你可以用AI去优化工作流程、提升效率、创造差异化优势。这是普通人真正能够“从内而变”的路径。

“世上本无路,走的人多了,便成了路。”如今这路就摆在眼前,关键在于:你是否肯走上一程。

参与门槛低

参与门槛的下降,是平民百姓的入口。

过去的技术红利,总是留给了少数受过高等教育、有资源、有背景的人。而AI不一样,它是一种“傻瓜式普惠技术”,越来越多的AI工具已经足够友好到“对话即可完成任务”。

而这,恰恰才是机遇扩散的关键。

只有当参与门槛足够低,价值的集中度才会高。
如果只有极少数人掌握入口,那岗位和机会也终将稀少。相反,门槛低,意味着千千万万普通人可以一同参与、共同创造,于是岗位才会多、场景才会活,活力才能持续。

要知道,大模型之前的AI,其实并不“亲民”。它非常垂直和孤岛化:你要搞清楚数据采集、算法建模、算力部署、软件开发、测试运维,最后还得做实际应用,哪一步都难如登天。AlphaGo虽然震撼世界,但它的能力只颠覆了围棋,换一个棋类,得从头来过。

大模型的意义,正是打通了从“技术”到“可用”的距离,让普通人得以使用、得以创造、得以受益。

AI的进步也许不会让人人皆成大师,但至少——人人皆有可能

AI时代个人机遇在哪

所以,AI时代的机会,不在“高处”,而在你脚下。

《传习录》中讲:“人须在事上磨,方立得住。”如今这“事”,便是你用AI能做出来的小结果、小产品、小解决方案。不是写PPT写出绝美模板,就是生成一页商业文案、五条短视频脚本、一个公司logo的初版、一份十分钟会议纪要的浓缩……

这些细碎的结果,就是新一代“微型商业体”的雏形。它也许不大,也许不高光,但它是真实的,它的门槛低,它能带来收入,它属于你。

如果AI是未来,那么LLM时代会出现AI时代的基础设施。

AI时代属于每一个参与它的人,肯把时光磨旧物, 也将微火照苍茫

image.png

为什么说AI是第四次工业革命

hzqiuxm阅读(84)

为什么说AI是第四次工业革命

引言

1.png

知来者之可追,察往者之可鉴。”要理解AI何以被称为第四次工业革命的标志,我们不妨先回望前三次工业革命的来路。

理解这条演进的脉络,才能看清我们身处时代的浪潮与方向。

理解了每次工业革命的底层逻辑后,就会更加清楚AI大模型的核心价值,才能被我们正确使用,而发挥出自身核心价值。

第一次革命:蒸汽的咆哮

18世纪60年代,英国引领了第一次工业革命的浪潮,蒸汽机的发明使马车让位于火车,帆船演化为汽轮船。
这次革命的底层逻辑,是劳动力的转变:人力、畜力、自然力被高密度、可控的化石能源所替代。由此,人类的生产效率突飞猛进,第一次真正摆脱了“靠天吃饭”的宿命。

正所谓“天行健,君子以自强不息”,这是人类第一次以技术之力,握住命运的缰绳。

2.png

第二次革命:电的光明

到了19世纪70年代,美国与德国推动了第二次工业革命的进程,电的广泛使用改变了世界的夜晚,催生了电灯、广播、电视等新兴产业。

它的底层逻辑,在于电的廉价与泛用性。这种能源不仅强大且便于传输,催生了传媒、娱乐等多个产业的变革,也为现代城市化铺设了基石。

若用古人的话说:“无垠万象,一电而通。”敏感的你是否开始联想到现在AI大模型的特点是不是也有着类似的味道?廉价的token,预训练大模型极强的泛化能力。电之于那个时代,如今日AI之于我们:低成本、高泛化、强传导性。token如电,模型如机,AI如光入万家。

此时此刻就如彼时彼刻。

3.png

第三次革命:信息之潮

20世纪40年代,美国率先开启了信息革命。第一台电子计算机虽庞大,但它带来的,是人类计算能力的指数级跃迁

这一时期的关键转变,是从体力劳作的替代,进入了脑力计算的延伸。芯片如同大脑的外接硬盘,而网络使信息如水般流通。

它的底层逻辑,劳动力的提升从体力开始变为了脑力,彻底改变了人类的通讯方式与工作、生活方式。我们第一次意识到:工具不再只是手足的延伸,更成为思维的延伸,人类开始以思维之力重构世界

4.png

第四次革命:AI到来

现在,我们站在第四次工业革命的门槛上。核心技术不再是单一能源或硬件工具,而是人工智能。这是一个融合5G、IOT、大数据与算法的新时代。

AI的核心变革,在于它不再仅仅辅助工作,而是进入“脑力劳动”本身,脑力多次重复劳动的基础性决策开始被替代:文本生成、数据分析、辅助决策、基础创意设计……

它的底层逻辑,标志着AI开始替代创作和决策这两个关键性的人类脑力劳动了。如果说前几次工业革命,是“手”与“足”的延伸,这次,则是“心”与“意”的激荡。AI的本质,是对“认知成本”的再革命。

人类千百年来思虑的问题——“我思,故我在”,正在被技术轻轻叩问:“机器亦思,你将如何在?”

5.png

吾将何在?革命正当时

每一次技术飞跃,都是一次文明的重组。要避免对AI的误解和盲目狂热,我们就必须像王阳明所言那样,“致良知”,知其所以然,而非仅见其然

AI不是神话,它是逻辑的产物,是算力、数据与算法三者交汇的必然结果。理解这三者之间的耦合方式,才能真正把握AI的核心价值与边界,而非迷信它能“替代一切”。

历史上,大多数人终其一生所处的社会形态,并无太多改变。一位宋代农人,其生活与其父祖并无太大差别,其一生所知所见,也不过百里之地。

而我们,却生在了一个“千年一遇”的时代。

“江山代有才人出,各领风骚数百年。”工业革命的浪潮,正如那滚滚长江水,奔涌向前。未来的工业革命,也许不会有太多轮次了。而这一次,或许就是你我亲历的最后一次

这不只是工程师的时刻,也不只是科技公司的浪潮——它是全人类的拐点时代

我们需要的不只是技术能力,更是价值判断与自我省察。正如《大学》所言:“格物、致知、诚意、正心”,我们需要用理性之光照亮技术的黑箱,以温柔的心性守护时代的锋利

参与这场革命,正当其时

Redis之路系列原理篇(5)

hzqiuxm阅读(2290)

5 原理篇—问渠哪得清如许

单线程模型

Redis的线程模型:基于NI/O、单线程、异步的线程模型
Redis基于Reactor模式开发了网络事件处理器,这个处理器叫做文件事件处理器(file event handler)。

这个文件事件处理器,是单线程的,采用I/O多路复用机制同时监听多个socket,它根据socket上的事件,来选择对应的事件处理器来处理这个事件。

下方是Redis单线程模型示意图:

文件事件处理器的结构包含4个部分:多个socket,I/O多路复用程序,文件事件分发器,事件处理器
客戶端与Redis通信的流程大致如下:

  • 1:客户端发出连接Redis的请求,产生 AE_READABLE事件,最后会关联到连接应答处理器,由它来负责真正处理跟客户端的连接
  • 2:客户端向Redis发出命令请求,产生 AE_READABLE事件,最后会关联到命令请求处理器,由它来从socket中获取相关数据,然后进行真正的执行处理
  • 3 :Redis处理完成请求过后,会准备好返回给客户端的数据,产生 AE_WRITABLE事件,最后会关联到命令回复处理器,由它来把数据写入到 socket,返回到客户端
  • 4 :命令回复处理器完成后,就会删除这个socket的 AE_WRITABLE事件和命令回复处理器之间的关联关系

事务

基本特点

Redis中的事务本质就是一组命令的集合,被依次顺序的执行,当然可以放弃事务的执行,那么所有事务里面的命令都不会执行。
Redis中的事务特点:

  • 单线程架构保证了执行完事务内所有指令前是不可能再去同时执行其他客户端的请求的
  • Redis的事务没有隔离级别的概念,不存在”事务内的查询要看到事务里的更新,在事务外查询不能看 到”这种问题了
  • Redis的事务不保证原子性,只有决定是否开始执行全部指令的能力,没有执行到一半进行回滚的能力

基本过程

  • 1 发送事务开始指令:multi
  • 2 依次发送执行命令
  • 3 依次执行命令:exec

注意:如果某命令有语法错误,那么所有命令都不会执行;如果某命令只是执行错误,其它命令会正常执行,之后返回错误信息,无法回滚

持久化

Redis持久化分成三种方式:RDB(Redis DataBase)、AOF (Append Only File)和AOF+RDB混合持久化

  • RDB:在不同的时间点,将Redis某一时刻的数据生成快照并存储到磁盘上(缺省打开)
  • AOF :只允许追加不允许改写的文件,是将Redis执行过的所有写指令记录下来,在下次Redis重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了(缺省关闭)
  • 混合方式:混合方式是先使用RDB进行快照存储,然后使用AOF持久化记录所有的写操作(redis6后推荐使用,缺省开启依赖RDB和AOF)。

RDB

默认情况下就是开启的

RDB方式,Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了, 再用这个临时文件替换上次持久化好的文件。

  • 主进程不进行任何的IO操作,确保了极高的性能

  • RDB是快照读取,大规模数据效率比AOF好,但可能会丢失最后一次持久化数据

  • 适合对数据完整性不是很敏感的场景,比如冷备份,可以高性能快速恢复数据

相关配置:

  • save * :保存快照的频率,第一个表示多长时间,单位是秒,第二个*表 示至少执行写操作的次数;在一定时间内至少执行一定数量的写操作时,就自动保存快照;可设置多个条件。

如果想禁用RDB持久化的策略,只要不设置任何save指令,或者给save传入一个空字符串参数也可以
如果用户开启了RDB快照功能,那么在Redis持久化数据到磁盘时如果出现失败,默认情况下,Redis会停止接受所有的写请求。

这样做的好处在于可以让用户很明确的知道内存中的数据和磁盘上的数据已经存在不一致 了。如果下一次RDB持久化成功,redis会自动恢复接受写请求。

  • dbfilename:数据快照文件名(只是文件名,不包括目录),默认dump.rdb,还可以把它当作冷备份使用
  • dir:数据快照的保存目录(这个是目录),默认是当前路径
  • stop-writes-on-bgsave-error:如果配置成no,表示你不在乎数据不一致或者有其他的手段发现和控制这种不一致,那么在快照写入失败时,也能确保 redis继续接受新的写请求
  • rdbcompression:对于存储到磁盘中的快照,可以设置是否进行压缩存储。 如果是的话,redis会采用LZF算法进行压缩。默认是开启的,如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能
  • rdbchecksum:在存储快照后,还可以让redis使用CRC64算法来进行数据校验 ,但是这样做会增加大约10%的性能消耗,默认是开启的,如果希望获取到最大的性能提升 ,可以关闭此功能
  • rdb-del-sync-files:在没有持久性的情况下删除复制中使用的RDB文件启用 。默认情况下,此选项是禁用的。

RDB模式要注意的一些问题:

  • fork一个进程时,内存的数据也被复制了,即内存会是原来的两倍。
  • 每次快照持久化都是将内存数据完整写入到磁盘一次,并不是增量的同步数据。如果数据量大的话,而且写操作比较多,必然会 引起大量的磁盘io操作,可能会严重影响性能。
  • 由于快照方式是在一定间隔时间做一次的,所以如果redis意外 down掉的话,就会丢失最后一次快照后的所有修改。

触发快照情况:

  • 根据配置规则进行自动快照
  • 用户执行save(阻塞所有客户端请求)或bgsave(后台异步处理)命令
  • 执行flushall命令,会清除内存中所有数据,然后生产rdb文件(数据全没了)
  • 执行复制replication时

AOF

将配置项appendonly设置为yes就可以打开AOF功能,默认是关闭的。

默认的AOF持久化策略是每秒钟fsync一次,fsync是指把缓存中的写指令记录到磁盘中,在这种情况下,Redis仍可以保持很高的性能。

  • OS会在内核中缓存Redis的写操作

  • 缓存不会立即写到磁盘上,会有一定的延迟,理论上是有数据丢失的可能性

  • 你可以修改配置,强制不要缓存直接写入磁盘中

  • Fsync的方式有三种,推荐每秒启用一次的everysec

  • 优点:更好的保护数据不丢失 、性能高、可做紧急恢复

  • 缺点:文件比RDB文件大、写的QPS比RDB低

相关配置:

  • appendonly:是否开启AOF,默认关闭

  • appendfilename:设置AOF的日志文件名

  • appendfsync:设置AOF日志如何同步到磁盘,fsync()调用,用来告诉操作系统立即将缓存的指令写入磁盘,有三个选项always(一般不用),everysec(推荐使用),no(操作系统自己决定同步时间)

  • no-appendfsync-on-rewrite:设置当redis在rewrite的时候,是否允许appendsync。因为redis进程在进行AOF重写的时候,fsync()在主进程中的调用会被阻止,也就是redis的持久化功能暂时失效。默认为no ,这样能保证数据安全

  • auto-aof-rewrite-min-size:设置一个最小值,是为了防止在aof很小时就触发重写

  • auto-aof-rewrite-percentage:设置自动进行AOF重写的基准值,也就是重写启动时的AOF文件大小,假如redis自启动至今还没有进行过重写,那么启动时aof文件的大小会被作为基准值。这个基准值会和当前的aof大小进行比较。如果当前aof大小超出所设置的增长比例,则会 触发重写。如果设置auto-aof-rewrite-percentage为0,则会关闭此重写功能

  • AOF持久化采用文件追加的方式,这会导致AOF文件越来越大,因为AOF相当与和写相关的操作日志,所以AOF设置了重写机制

  • 重写机制就是当AOF超过一定大小,就会启动文件内容压缩,只保留可以恢复数据的最小指令集

  • 主动触发重写命令bgrewriteaof

重写基本流程:

  • 1 在重写开始前,redis会创建一个“重写子进程”,这个子进程会读取现有的 AOF文件,并将其包含的指令进行分析压缩并写入到一个临时文件中。
  • 2 与此同时,主进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的AOF文件中,这样做是保证原有的AOF文件的可用性,避免在重写过程中出现意外。
  • 3 当“重写子进程”完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新AOF文件中
  • 4 当追加结束后,redis就会用新AOF文件来代替旧AOF文件,之后再有新的写指 令,就都会追加到新的AOF文件中
  • 5 重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似

AOF日志恢复
如果在追加日志时,恰好遇到磁盘空间满或断电等情况,导致日志写入不完整,也没有关系,Redis提供了redis-check-aof工 具,可以用来进行日志修复,基本步骤如下:

  • 备份被写坏的AOF文件
  • 运行redis-check-aof –fix进行修复
  • 用diff -u来看下两个文件的差异,确认问题点
  • 重启redis,加载修复后的AOF文件

混合模式

先使用RDB进行快照存储,然后使用 AOF持久化记录所有的写操作,当重写策略满足或手动触发重写的时候,将最新的数据存储为新的RDB记录。

这样的话,重启服务的时候会从RDB和AOF两部分恢复数据, 既保证了数据完整性,又提高了恢复数据的性能。

通过 aof-use-rdb-preamble 配置项可以打开混合方式,默认是yes。
所以日志文件中会同时包含了RDB数据和AOF数据

数据恢复顺序:

  • 1 判断是否开启AOF持久化,若开启了AOF,则使用AOF持久化文件恢复数据
  • 2 如果AOF文件不存在,否则使用RDB持久化文件恢复数据
  • 3 如果AOF文件和RDB文件都不存在则直接启动Redis
  • 4 如果AOF或RDB文件出现错误,则启动失败返回错误信息

附录1:Redis事务基本命令

  • 1:multi:设置事务开始
  • 2:exec:执行事务
  • 3:discard:放弃事务
  • 4:watch:监控键值,如果键值被修改或删除,后面的一个事务就不 会执行
  • 5:unwatch:取消watch

关于watch:Redis使用Watch来提供乐观锁定,类似于CAS;可以被调用多次;当 EXEC 被调用后,所有的之前被监视的键值会被取消监视,不管事务是否被取消或者执行。并且当客户端连接丢失的时候,所有东 西都会被取消监视

Redis之路系列拓展篇(4)

hzqiuxm阅读(2750)

4 拓展篇—功夫在诗外

6.0新特性

相对都比较鸡肋,谨慎在生产环境使用

ACL安全策略

Redis6版本推出了ACL(Access Control List)访问控制权限 的功能,基于此功能,可以设置多个用户,并且给每个用户单独设 置命令权限和数据权限。

ACL文件配置方式有两种,一种是在config文件中直接配置,另一种是在外部aclfile中配置,配置命令是一样的
ACL是使用DSL定义的,该规则是从上到下,从左到右的,具体可以参考附录中的具体规则说明

RESP3和客户端缓存

RESP(REdisSerializationProtocol),是 Redis服务端与客户端之间通信的协议。
在Reds6之前的版本,使用的是RESP2协议,数据都是以字符串数组的形式返回给客户端,客户端需要根据类型进行解析,增加了客户端实现的复杂度。
RESP3协议可以按类型返回数据。 可以使用HELLO命令在RESP2和RESP3协议之间进行切换

新增的客户端缓存的设计导致客户端缓存和redis缓存绑定,十分不灵活,会导致资源浪费,没有很大的实际使用价值。

Redis中值的变化每次需要同步到客户端缓存,但是客户端并非会用到没的变化,导致资源浪费,数据管理更加复杂了,实际价值不大

I/O多线程

注意:主流程操作还是单线程
开启IO多线程:io-threads-do-reads yes 配置线程数量,如果设为1就是主线程模式:io-threads 4

目前官方建议:至少4核的机器才开启IO多线程,并且除非真的遇到了性能瓶颈,否则不建议开启此配置 。 建议配置的线程数少于机器总线程数,线程并不是越多越好 ,多于8个线程意义不大

集群代理

集群代理把集群抽象成为单个Redis实例,客户端通过集群 代理访问集群,就像访问单个Redis一样,不去关心很多集群上 的问题,比如:集群模式下multiple操作的限制及跨slot操作限 制等等,这些由集群代理去处理。

目前是一个实验性的功能,需要单独安装、单独配置、单独运行,不建议生产环境使用。

Lua脚本

Lua是一个高效、简洁、轻量级、可扩展的脚本语言,可以很方便的嵌入到其它语言或中间件中使用,Redis从2.6版支持Lua。

使用脚本好处

  • 1:减少网络开销
  • 2:原子操作:Redis会把脚本当作一个整体来执行,中间不会插入其它命令
  • 3:复用功能

基本数据类型

Lua是一个动态类型的语言,一个变量可以存储任何类型的值

基础语法

  • 默认全局变量,但是在Redis中不允许使用,局部变量使用local关键字进行声明
  • 变量名必须是非数字开头,只能包含字母、数字和下划线
  • 变量名是区分大小写
  • 逻辑操作符用单词表示:and、or、not
  • 单行注释使用 --来表示,多行注释使用--[[ 开始,到 ]] 结束
  • 支持多重赋值:local a,b = 1,2,3 (a=1,b=2),不过不建议,难维护易错
  • 使用 .. 用来连接字符串
  • 使用 #来获取长度,比如:print(#'helloworld')
  • 只有nil和false是假,其它都是真
  • 循环语句有for、while、repeat三种

与Redis结合

在Redis中执行lua脚本命令: redis-cli --eval 脚本 [key...] , [arg...]
在脚本中调用Redis命令:redis.call,遇到错误会直接返回;想要继续执行使用redis.pcall命令

Lua数据类型与Redis返回值类型对应关系:

其它命令:

  • evalsha:可以通过脚本摘要来运行,作用同eval
  • script load:将脚本加入缓存,返回值就是SHA1摘要
  • script exists:判断脚本是否已经缓存
  • script flush:清空脚本缓存
  • script kill:强制终止脚本的执行

发布订阅模式

Redis支持简单的发布订阅模式,可以实现进程间的消息传递,对业务要求不高的可以选择使用
下面是一些常用的操作命令:

  • 1:publish:发布消息,格式是publish channel 消息
  • 2:subscribe:订阅频道,格式是subscribe channel,可以是多个channel
  • 3:psubscribe:订阅频道,格式是psubscribe channel,支持glob风格的通配符
  • 4:unsubscribe:取消订阅,格式是unsubscribe channel,不指定频道表示取消所有subscribe命令的订阅
  • 5:punsubscribe:取消订阅,格式是punsubscribe channel,不指定频道表示取消所有psubscribe命令的订阅

注意这里匹配模式的时候,是不会将通配符展 开的,是严格进行字符串匹配的,比如:punsubscribe * 是无法退定 c1.* 的,必须严格使用punsubscribe c1.*才可以

常用优化手段

  • 使用管道Pipeline,有利于减少网络通信和传输
  • 精简键名和键值
  • 合理设计存储的数据结构和数据关系,减少数据冗余
  • 尽量使用mset来赋值,类似还有lpush、zadd等批量操作的命令
  • 如果可能,尽量使用Lua脚本来辅助获取和操作数据
  • 尽量使用hash结构来存储对象
  • 使用hash结构时,应尽量保证每个key下面<field,value>的数目不超过限制(默认值是64)
  • 配置使用类似ziplist以优化list等数据结构
  • 一定要设置maxmemory,保证redis不会因为内存导致崩溃

客户端

Lettuce简介

Lettuce是一个可伸缩线程安全的Redis客户端。多个线程可以共享同一个RedisConnection。它利用优秀netty NIO框架来高效地管理多个连接。

Lettuce核心组件有:RedisURI、Connection、RedisClient、RedisCommands

  • RedisURI:封装Redis的连接信息
  • Connection:Redis的连接,包含一些具体方式(单机、哨兵、集群、订阅发布等)
  • RedisClient:Redis的客户端,如果连接集群则为RedisClusterlient
  • RedisCommands:Redis的命令操作API接口,提供了三种调用方式:同步、异步、响应式

基本使用

官网地址:https://lettuce.io/docs/getting-started.html

基本依赖:

dependencies {
  compile 'io.lettuce:lettuce-core:6.1.4.RELEASE
}

基本使用示例:

RedisClient redisClient = RedisClient.create("redis://password@localhost:6379/0");
StatefulRedisConnection<String, String> connection = redisClient.connect();
RedisCommands<String, String> syncCommands = connection.sync();

syncCommands.set("key", "Hello, Redis!");

connection.close();
redisClient.shutdown();

与Spring的集成

@Configurationclass AppConfig { @Beanpublic LettuceConnectionFactory redisConnectionFactory() { return new LettuceConnectionFactory(new RedisStandaloneConfiguration("server", 6379)); } }

附录1:Lua脚本常用标准库与函数

Lua的标准库提供了很多使用的功能,Redis支持其中大部分:

  • 1:Base:提供一些基础函数
  • 2:String:提供用于操作字符串的函数
  • 3:Table:提供用于表操作的函数
  • 4:Math:提供数据计算的函数
  • 5:Debug:提供用于调试的函数

除了标准库外,Redis还会自动加载cjson和cmsgpack库,以提供对 Json和MessagePack的支持,在脚本中分别通过cjson和cmsgpack两 个全局变量来访问相应功能

在Redis中常用的标准库函数:

  • 1:string.len(string)
  • 2:string.lower(string)
  • 3:string.upper(string)
  • 4:string.rep(s, n):返回重复s字符串n次的字符串
  • 5:string.sub(string,start[,end]),索引从1开始,-1表示最后一 个
  • 6:string.char(n…):把数字转换成字符
  • 7:string.byte (s [, i [, j]]):用于把字符串转换成数字
  • 8:string.find (s, pattern [, init [, plain]]):查找目标模板 在给定字符串中出现的位置,找到返回起始和结束位置,没找到返 回nil
  • 9:string.gsub (s, pattern, repl [, n]):将所有符合匹配模式的 地方都替换成替代字符串。并返回替换后的字符串,以及替换次数 。四个参数,给定字符串,匹配模式、替代字符串和要替换的次数
  • 10:string.match (s, pattern [, init]):将返回第一个出现在给 定字符串中的匹配字符串,基本的模式有:. 所有字符,%a字母, %c控制字符,%d数字,%l小写字母,%p 标点符号字符,%s 空格, %u 大写字母,%w 文字数字字符,%x 16进制数字等
  • 11:string.reverse (s):逆序输出字符串
  • 12:string.gmatch (s, pattern):返回一个迭代器,用于迭代所有出现 在给定字符串中的匹配字符串
  • 13:table.concat(table[,sep[,i[,j]]]):将数组转换成字符串,以sep 指定的字符串分割,默认是空,i和j用来限制要转换的表索引的范围 ,默认是1和表的长度,不支持负索引
  • 14:table.insert(table,[pos,]value):向数组中插入元素,pos为指定 插入的索引,默认是数组长度加1,会将索引后面的元素顺序后移
  • 15:table.remove(table[,pos]):从数组中弹出一个元素,也就是删除这 个元素,将后面的元素前移,返回删除的元素值,默认pos是数组长度 table.sort(table[,sortFunction]):对数组进行排序,可以自定义 排序函数
  • 16:Math库里面常见的:abs、ceil、floor、max、min、pow、sqrt、 sin、cos、tan等
  • 17:math.random([m[,n]]):获取随机数,如果是同一个种子的话, 每次获得的随机数是一样的,没有参数,返回0-1的小数;只有m, 返回1-m的整数;设置了m和n,返回m-n的整数
  • 18:math.randomseed(x):设置生成随机数的种子

附录2:ACL规则

启用和禁用用户

  • on:启用用户
  • off:禁止用户

允许和禁止调用

  • +:将命令添加到用户可以调用的命令列表中
  • -:将命令从用户可以调用的命令列表中移除
  • +@:允许用户调用 类别中的所有命令
  • -@:禁止用户调用 类别中的所有命令
  • +|subcommand:允许使用已禁用命令的特定子命令
  • allcommands:+@all的别名,包括当前存在的命令以及将来通过模块加载的所有命令
  • nocommands:-@all的别名,禁止调用所有命令

允许或禁止访问key

  • ~:添加可以在命令中使用的键模式
    • resetkeys:使用当前模式覆盖所有允许的模式

为用户配置有效密码

  • >:将此密码添加到用户的有效密码列表中
  • <:从有效密码列表中删除此密码
  • #:将此SHA-256哈希值添加到用户的有效密码列表中
  • !:从有效密码列表中删除该哈希值
  • nopass:移除该用户已设置的所有密码
  • resetpass:清空该用户的所有密码列表
  • reset:重置用户状态为初始状态

PS:具体命令可以通过acl help 查看

Redis之路系列集群篇(3)

hzqiuxm阅读(2317)

3 集群篇—众人拾柴火焰高

复制

基本概述

Redis支持复制的功能,以实现当一台服务器的数据更新后,自动将新的数据异步同步到其它数据库。

Redis复制实现中,把数据库分为主数据库master和从数据库slave ,主数据库可以进行读写操作,从数据库默认是只读的,当主数据库数据变化的时候,会自动同步给从数据库。

主从复制的结构支持一个Mater带多个Slave,也可以Slave带Slave模式

复制的好处:

  • 可以实现读写分离
  • 在主数据崩溃时可以实现数据恢复
  • 可进行水平扩容支撑高并发

基本配置

  • 配置原则 :主数据库不做配置,从数据库中设置 replicaof 主数据库ip 主数据库port

具体的配置请查阅附录一

基本原理

  • 全量复制

  • slave启动时,会向master发送psync请求,如果这是slave重新连 接master,那么master仅仅会复制给slave缺少的数据; 如果是第 一次连接master,那么会触发一次全量复制
  • 主数据库接到psync请求后,如果是全量复制,会在后台保存快照 ,就是实现RDB持久化,并将保存快照期间接收到的命令缓存起来
  • 快照完成后,主数据库会将快照文件和所有缓存的命令发送给从数据库
  • 从数据库接收后,会载入快照文件并执行缓存的命令,从而完成复 制的初始化

  • 增量复制

  • 如果是重新连接,Master会检查backlog里面的offset, master和 slave都会保存一个复制的offset还有一个master id,offset是保 存在backlog中的。Master只会把已经复制的offset后面的数据复 制给Slave,类似断点续传
  • 在数据库使用阶段,主数据库会自动把每次收到的写命令同步到从 服务器
  • Slave在复制的时候,不会阻塞Master的正常工作;也不会阻塞对 自己的查询操作,它会用旧的数据集来提供服务; 但是复制完成的 时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外 服务了

PS:Master一定要持久化

  • 乐观复制策略:Redis采用乐观复制的策略,容忍在一定时间内主从数据库 的内容不同,当然最终的数据会是一样的。

这个策略保证了性能, 在复制的时候,主数据库并不阻塞,照样处理客户端的请求。 Redis提供了配置来限制只有当数据库至少同步给指定数量 的从数据库时,主数据库才可写,否则返回错误。配置是:min-replicas-to-write、min-replicas-max-lag

  • 无硬盘复制:Master直接创建一个子进程,来生成RDB文件的内容,并通 过网络直接传送给Slave,也就是RDB文件不保存到磁盘上。

数据丢失解决方案

  • 异步复制导致丢失:master宕机,在主备切换的过程中,可能会导致数据丢失。
  • 主从脑裂导致丢失:网络原因导致master短时间脱离集群,集群产生了新master,但客户端仍然往旧mater写数据,网络恢复后,旧master变成slave与新mater同步导致数据丢失。

解决方案:配置min-replicas-to-write和min-replicas-max-lag两个参数,比如: min-replicas-to-write 1 、 min-replicas-max-lag 10。

要求至少有1个slave,数据复制和同步的延迟不能超过10秒。

一旦所有的slave,数据复制和同步的延迟都超过了10秒钟, 那么这个时候,master就不会再接收任何请求了。

脑裂情况下,一个master跟其它slave丢了连接,那么这两个配置可以确保,如果不能继续给指定数量的slave发送数据,而且slave 超过10秒没有给自己应答消息,那么就直接拒绝客户端的写请求。

哨兵

基本概述

哨兵是Redis 复制集集群的重要组件,它的主要作用有:

  • 集群监控:监控主从数据库运行是否正常
  • 故障转移:当主数据库出现故障时,自动将从数据库转换成为主数据库
  • 配置中心:客户端通过连接哨兵来获得当前Redis服务的主节点地址
  • 消息通知:哨兵可以将故障转移的结果发送给客户端

开启哨兵功能需要建立一个个sentinel.conf文件,里面设置要监控的主数据库的名字,比如:sentinel monitor 监控的主数据库的名字 127.0.0.1 6380 1

其中数字1表示的是哨兵判断主节点是否法神故障的最低票数,这个文件在运行期间会被sentinel动态进行更改,可以同时监控多个主数据库,一行一个配置即可,详细的配置参考附录二。

哨兵集群在整个主从集群中的功能关系结构图如下:

主从节点存放数据,而哨兵节点用来自动监控和维护集群,不存放数据
每个哨兵节点维护了3个定时任务:

  • 1 哨兵向master-slave节点发送info命令来获取复制集的结构
  • 2 哨兵之间通过pub/sub系统来互相感知装态和信息
  • 3 哨兵向master-slave节点发送ping命令来进行心跳检测

基本原理

  • SDown:主观下线,在心跳检测的定时任务中,如果其它节点超过一定时间没有回复, 哨兵节点就会将其进行主观下线。也就是说,主观下线的意思是一个哨兵节点“主观地”判断某个节点下线

  • ODown:客观下线,哨兵节点在对主节点进行主观下线后,会通过sentinel is-master-down-by-addr命令询问其它哨兵节点该主节点的状态;如果判断主节点下线的哨兵数量达到一定数值,则对该主节点进行客观下线。

哨兵四大基本原理:自动发现、选举领导、故障转移、配置传播

  • 自动发现
    哨兵互相之间的相互自动发现,是通过redis的pub/sub系统实现的 ,每个哨兵都会往sentinel:hello这个channel里发送一个消息,这时 候所有其他哨兵都可以消费到这个消息,并感知到其他的哨兵的存在。

每隔两秒钟,每个哨兵都会往自己监控的某个master+slave对应的 sentinel:hello channel里发送一个消息,内容是自己的host、ip和 runid还有对这个master的监控配置。

每个哨兵也会去监听自己监控的每个master+slaves对应的 sentinel:hello channel,然后去感知到同样在监听这个 master+slave的其他哨兵的存在。

每个哨兵跟其他哨兵交换对master的监控配置,互相进行监控配置 的同步

  • 选举领导:选举出领导者哨兵

哨兵选举涉及两个参数:quorum(确认客观下线的最少的哨兵数量),majority(授权进行主从切换的最少的哨兵数量)

每次一个哨兵要做主备切换,首先需要quorum数量的哨兵认为master客观下线,然后选举出一个哨兵来做切换,这个哨兵还需要得到majority哨兵的授权,才能正式执行切换

当主节点被判断客观下线以后,各个哨兵节点会进行协商, 选举出一个领导者哨兵节点,并由该领导者节点对其进行故障转移操作。

监视该主节点的所有哨兵都有可能被选为领导者,选举使用的算法是Raft算法;Raft算法的基本思路是先到先得:即在一轮选举中,哨兵A向B发送成为领导者的申请,如果B没有同意过其他哨兵,则会同意A成为领导者

  • 故障转移:选举出的领导者哨兵,开始进行故障转移操作,选举出新mater节点,大体可以分为3个步骤

1 在从节点中选择新的主节点:选择的原则是,首先过滤掉不健康的从节点; 然后选择优先级最高的从节点(由slave-priority指定);如果优先级无法区分,则选择复制offset最大的从节点;如果仍无法区分,则选择runid最小的从节点

2 更新主从状态:通过slaveof no one命令,让选出来的从节点成为主节点; 并通过slaveof命令让其他节点成为其从节点

3 将已经下线的主节点设置为新的主节点的从节点,当其重新上线后,它会成为新的主节点的从节点

  • 配置传播
    新的master选出过后,执行切换的那个哨兵,会从要切换到的新master那里得到一个configuration epoch,这就是一个 version号,每次切换的version号都必须是唯一的。

如果第一个选举出的哨兵切换失败了,那么其他哨兵,会等待failover-timeout时间,然后接替继续执行切换,此时会重新获取一个新的configuration epoch,作为新的version号。

哨兵完成master切换之后,会在自己本地更新生成最新的master配置,然后同步给其他的哨兵,就是通过之前说的pub/sub 消息机制。

这时version号就很重要了,因为各种消息都是通过一个 channel去发布和监听的,所以一个哨兵完成一次master的切换之 后,新的master配置是跟着新的version号的。

其他的哨兵都是根据版本号的大小来更新自己的master配置的。

使用建议

  • 哨兵节点的数量应为多个,哨兵本身应该集群,保证高可用
  • 哨兵节点的数量应该是奇数
  • 各个哨兵节点的配置应一致

另外如果哨兵节点部署在Docker等容器里面,尤其要注意端口的正确映射,还需要知道哨兵集群+主从复制,并不能保证数据零丢失

分片

由于复制中,每个数据库都是拥有完整的数据,因此复制的 总数据存储量,受限于内存最小的数据库节点,如果数据量过大, 复制就无能为力了。

这个时候就需要用到分片技术,分片是将数据拆分到多个Redis实例的过程,这样每个Redis实例将只包含完整数据的一部分。

常见的分片方式有:按范围分片和哈希分片

分片实现方式

  • 在客户端进行分片
  • 通过代理来进行分片,比如:Twemproxy
  • 查询路由:就是发送查询到一个随机实例,这个实例会保证转发你的查询到正确的节点,Redis集群在客户端的帮助下,实现了查询路由的一种混合形式,请求不是直接从Redis实例转发到另一个, 而是客户端收到重定向到正确的节点(客户端启动时,加上-c参数)
  • 在服务器端进行分片, Redis采用哈希槽(hash slot)的方式在服务器端进行分片:Redis集群有16384个哈希槽,使用键的CRC16 编码对16384取模来计算一个键所属的哈希槽

分片缺点

  • 不支持涉及多键的操作,如mget,如果所操作的键都在同一个节点 ,就正常执行,否则会提示错误
  • 分片的粒度是键,因此每个键对应的值不要太大
  • 数据备份会比较麻烦,备份数据时你需要聚合多个实例和主机的持 久化文件
  • 扩容的处理比较麻烦
  • 故障恢复的处理会比较麻烦,可能需要重新梳理Master和Slave的 关系,并调整每个复制集里面的数据

结论:尽量避免去使用分片概念

集群架构

基本概念

由于数据量过大,单个复制集难以承担,因此需要对多个复制集进行集群,形成水平扩展,每个复制集只负责存储整个数据集的一部分,这就是Redis的集群。

分片可以模拟实现集群效果,但是有非常多的缺点,已经不推荐使用
现在Redis支持集群,在不降低性能的情况下,还提供了网络分区后的 可访问性和支持对主数据库故障的恢复。

  • redis集群支持多个Master,每个Master可以挂载多个Slave,便于支持读写分离
  • 集群Cluster内置了高可用的支持,无需再去使用哨兵的功能
  • 集群中所有节点彼此互相连接,内部使用二进制协议(gossip)来进行优化传输速度和带宽
  • 客户端与任一节点直接连接即可访问集群数据
  • 集群负责把插槽分配到各个物理服务节点,由集群来负责维护节点、插槽、数据之间关系

使用集群后,都只能使用默认的0号数据库

每个Redis集群节点需要两个TCP连接打开,正常的TCP端口用来服 务客户端,例如6379,加10000的端口用作数据端口,必须保证防火墙打开这两个端口

Redis集群不保证强一致性,这意味着在特定的条件下,Redis集群 可能会丢掉一些被系统收到的写入请求命令。

手工创建集群

集群的最低标准6个redis实例:3个master节点,每个master带一个slave节点
集群创建的步骤大致 如下:

  • 1 集群配置:将每个数据库的cluster-enabled配置选项打开,然 后再修改如下内容:pidfile、port、logfile、dbfilename、 cluster-config-file
  • 2 启动数据库:分别启动这些Redis数据库,可以用info cluster查看信息
  • 3 连接节点:使用cluster meet,把所有的数据库都放到一个集群中,可以通过cluster info ,或者cluster nodes 查看信息
  • 4 设置slave::设置部分数据库为slave,使用cluster replicate
  • 5 分配插槽:使用cluster addSlots,这个命令目前只能一个一个加,如果要加区间的话,就得客户端编写代码来循环添加。有个实用的技巧:把所有的Redis停下来,然后直接修改node-xxx.conf 的配置文件,只需要配置master的数据库就可以,然后再重启数据库。分配完记得用使用cluster slots命令检查下

最后,通过cluster info查看集群信息,如果显示ok,那就可以使用了

插槽与预分区

插槽

插槽是Redis对Key进行分片的单元。在Redis的集群实现中 ,内置了数据自动分片机制,集群内部会将所有的key映射到16384个插槽中,集群中的每个数据库实例负责其中部分的插槽的读写。

键与插槽的关系:Redis会将key的有效部分,使用CRC16算法计算出散列值, 然后对16384取余数,从而把key分配到插槽中。

键名的有效部分规则是:如果键名包含{},那么有效部分就是{}中的值;否则就是取整个键名

可以看成是集群数据的逻辑划分,也是redis内存的逻辑划分

移动已分配的插槽,这个稍微麻烦点,尤其是有了数据过后,假设要迁移123号插槽从A 到B,大致步骤如下:

  • 1:在B上执行cluster setslot 123 importing A
  • 2:在A上执行cluster setslot 123 migrating B
  • 3:在A上执行cluster getkeysinslot 123 要返回的数量
  • 4:对上一步获取的每个键执行migrate命令,将其从A迁移到B
  • 5:在集群中每个服务器上执行cluster setslot 123 node B (集群其实会自动同步,不过有延迟)

避免键的临时丢失:上面迁移方案中的前两步就是用来避免在移动已分配插槽过 程中,键的临时丢失问题的,大致思路如下

1 当前两步执行完成后,如果客户端向A请求插槽123中的键时,如果 键还未被转移,A将处理请求
2 如果键已经转移,则返回,把新的地址告诉客户端,客户端将发起 新的请求以获取数据

当客户端向某个数据库发起请求时,如果键不在这个数据库里面,将会返回一个move重定向的请求,里面包含新的地址,客户端收到这个信息后,需要重新发起请求到新的地址去获取数据。

当然,大部分的Redis客户端都会自动去重定向,也就是这个过程对开发人员是透明的。redis-cli也支持自动重定向,只需要在启动时加入 -c 的 参数。

预分区

为了实现在线动态扩容和数据分区,Redis的作者提出了预分区的方案,实际就是在同 一台机器上部署多个Redis实例,当容量不够时将多个实例拆分到不同的机器上,这样就达到了扩容的效果。

  • 1:在新机器上启动好对应端口的Redis实例
  • 2:配置新端口为待迁移端口的从库
  • 3:待复制完成,与主库完成同步后,切换所有客户端配置到新的从库的端口
  • 4:配置从库为新的主库
  • 5:移除老的端口实例
  • 6:重复上述过程把要迁移的数据库转移到指定服务器上

以上拆分流程是Redis作者提出的一个平滑迁移的过程,不过该拆分方法还是很依赖Redis本身的 复制功能的,如果主库快照数据文件过大,这个复制的过程也会很久,同时会给主库带来压力。

集群故障恢复

故障判定

  • 集群中每个节点都会定期向其他节点发出ping命令,如果没有收到回复,就 认为该节点为疑似下线,然后在集群中传播该信息
  • 当集群中的某个节点,收到半数以上认为某节点已下线的信息,就会真的标 记该节点为已下线,并在集群中传播该信息
  • 如果已下线的节点是master节点,那就意味着一部分插槽无法写入了
  • 如果集群任意master挂掉,且当前master没有slave,集群进入fail状态
  • 如果集群超过半数以上master挂掉,无论是否有slave,集群进入fail状态
  • 当集群不可用时,所有对集群的操作做都不可用,客户端会收到The cluster is down错误信息

故障恢复

发现某个master下线后,集群会进行故障恢复操作,来将一个slave 变成master,基于Raft算法,大致步骤如下:

  • 1:某个slave向集群中每个节点发送请求,要求选举自己为master
  • 2:如果收到请求的节点没有选举过其他slave,会同意
  • 3:当集群中有超过节点数一半的节点同意该slave的请求,则该Slave选举成功
  • 4:如果有多个slave同时参选,可能会出现没有任何slave当选的情况,将会等 待一个随机时间,再次发出选举请求
  • 5:选举成功后,slave会通过 slaveof no one命令把自己变成master

如果故障后还想集群继续工作,可设置cluster-require-full-coverage为 no,默认yes。

另外要弄清楚master挂掉了,重启还可以加入集群,只是变成Slave;但挂掉的slave重启,如果对应的master变化了,是不能加入集群 的,除非修改它们的配置文件,将其原master指向新master。

只要主从关系建立,就会触发主和该从采用save方式持久化数据, 不论你是否禁止save。

在集群中,如果默认主从关系的主挂了并立即重启,如果主没有做持久化,数据会完全丢失,从而从的数据也被清空。

建议恢复机制交给集群自己去处理,不要使用脚本来控制master的启停,操作不当会导致数据完全丢失

附录一:复制常用配置

关于复制一些基本操作命令:

  • info replication :可以查看复制节点的相关信息(info是一个非常强大的命令,可以查看很多信息比如内存、cpu等)
  • slaveof:可在运行期间修改slave节点的信息,如果该数据库已经是某个主数据库的从数据库,那么会停止和原主数据库的同步关系 ,转而和新的主数据库同步
  • slaveof no one:使当前数据库停止与其他数据库的同步,转成主数据库,不影响它的slave节点
  • replicaof :指定某一个redis作为另一个redis的从服务器,通过指定IP和端口来设置主redis
  • masterauth:如果主redis设置了验证密码的话(使用requirepass来设置),则在从redis的配置中要使用masterauth来设置校验密码,否则的话,主redis会拒绝从redis的访问请求
  • replica-read-only:设置从Redis为只读
  • repl-ping-replica-period:设置从redis会向主redis发出PING包的周期,默认是10秒
  • replica-serve-stale-data:设置当从redis失去了与主redis的连接,或者主从同步正在进行中时,redis该如何处理外部发来的访问请求,默认是yes

如果设置为yes(默认),则从redis仍会继续响应客户端的 请求。如果设置为no,则从redis会对客户端的请求返回“SYNC with master in progress”,当然也有例外,当客户端发来INFO 请求和SLAVEOF请求,从redis还是会进行处理。

  • repl-timeout:设置主从同步的超时时间,要确保这个时限比 repl-ping-replica-period的值要大,否则每次主redis都会认为从redis超时
  • repl-disable-tcp-nodelay:设置在主从同步时是否禁用 TCP_NODELAY,如果开启,那么主redis会使用更少的TCP包和更少的带宽来向从redis传输数据。但是这可能会增加一些同步的延迟 ,大概会达到40毫秒左右。如果关闭,那么数据同步的延迟时间会降低,但是会消耗更多的带宽
  • repl-backlog-size:设置同步队列长度。队列长度(backlog)是 主redis中的一个缓冲区,在与从redis断开连接期间,主redis会用这个缓冲区来缓存应该发给从redis的数据。这样的话,当从redis重新连接上之后,就不必重新全量同步数据,只需要同步这部分增量数据即可。默认是1M,可根据实际业务情况进行调整。
  • repl-backlog-ttl:设置主redis要等待的时间长度,如果主redis 等了这么长时间之后,还是无法连接到从redis,那么缓冲队列中的数据将被清理掉。设置为0,则表示永远不清理。默认是1个小时,应该足够了。
  • replica-priority:设置从redis优先级,在主redis持续工作不 正常的情况,优先级高的从redis将会升级为主redis。而编号越小 ,优先级越高。当优先级被设置为0时,这个从redis将永远也不会 被选中。默认的优先级为100。
  • min-replicas-to-write:设置执行写操作所需的最少从服务器数量,如果至少有这么多个从服务器, 并且这些服务器的延迟值都 少于 min-replicas-max-lag 秒, 那么主服务器就会执行客户端 请求的写操作,该配置保证其高可用性,默认是0
  • min-replicas-max-lag:设置最大连接延迟的时间, min-replicas-to-write和min-replicas-max-lag中有一个被置为0,则这个特性将被关闭。默认min-replicas-max-lag为10
  • repl-diskless-sync:是否开启无盘复制,通过网络完成复制而不是RDB文件,默认是no
  • repl-diskless-sync-delay:设置无盘复制延时开始秒数,默认是5秒 ,意思是当PSYNC触发的时候,master延时多少秒开始向slave传送数 据流,以便等待更多的slave连接可以同时传送数据流,因为一旦 PSYNC开始后,如果有新的slave连接master,只能等待下次PSYNC。可以配置为0取消等待,立即开始
  • repl-diskless-load:是否使用无磁盘加载,这是个实验性的功能,知道下就可以

附录二:哨兵常用配置

  • bind:服务监听地址,用于客户端连接,默认本机地址
  • protected-mode:安全保护模式
  • port:监听的端口号
  • daemonize:是否以后台daemon方式运行
  • pidfile:pid文件位置
  • logfile:log文件位置
  • dir:工作目录
  • sentinel monitor :设置要监控的 master服务器
  • sentinel auth-pass :连接master服务的密码
  • sentinel down-after-milliseconds :指定多少毫秒之后,主节点没有应答哨兵,此时哨兵主观上认为主节点下线
  • sentinel parallel-syncs :表示允许并行同步的 slave个数,当Master挂了后,哨兵会选出新的Master,此时剩余的slave会向新的master发起同步数据
  • sentinel failover-timeout :故障转移的超时时间,进行故障转移时,如果超过设置的毫秒,表示故障转移失败
  • sentinel notification-script :配置当某一事件发生时所需要执行的脚本
  • sentinel client-reconfig-script :客户 端重新配置主节点参数脚本

附录三:常见集群操作命令

  • CLUSTER INFO:获取集群的信息
  • CLUSTER NODES:获取集群当前已知的所有节点,以及这些节点的相关信息
  • CLUSTER MEET :将ip和port所指定的节点添加到集群当中
  • CLUSTER FORGET :从集群中移除 node_id 指定的节点
  • CLUSTER REPLICATE :将当前节点设置为 node_id 指定 的节点的从节点
  • CLUSTER SAVECONFIG:将节点的配置文件保存到硬盘里面
  • CLUSTER ADDSLOTS [slot ...]:将一个或多个槽分配给当 前节点
  • CLUSTER DELSLOTS [slot ...]:从当前节点移除一个或多 个槽
  • CLUSTER FLUSHSLOTS:移除分配给当前节点的所有槽
  • CLUSTER SETSLOT NODE :将槽分配 给 node_id 指定的节点,如果槽已经分配给另一个节点,那么先 让另一个节点删除该槽>,然后再进行分配
  • CLUSTER SETSLOT MIGRATING :将本节点的槽 迁移到指定的节点中
  • CLUSTER SETSLOT IMPORTING :从指定节点导 入槽到本节点
  • CLUSTER SETSLOT STABLE :取消对槽的导入(import)或 迁移(migrate)
  • CLUSTER KEYSLOT :计算键 key 应该被放置在哪个槽
  • CLUSTER COUNTKEYSINSLOT :返回槽目前包含的键值对数 量
  • CLUSTER GETKEYSINSLOT :返回count个槽中的键
  • migrate 目的节点ip 目的节点port 键名 数据库号码 超时时间 [copy] [replace]:迁移某个键值对

附录四:常见集群配置

  • cluster-enabled :是否开启集群模式
  • cluster-config-file: 集群配置文件,由Redis集群节点自动维护每次配置的改变
  • cluster-node-timeout:超时时间,集群节点不可用的最大时间
  • cluster-replica-validity-factor:集群副本有效因子,如果发生故障的Master数据看起来太旧,则其副本将避免进行故障转移
    如果设置为0,则slave将总是尝试故障转移。如果设置为一个正数,那么最大失去连接的时间是node timeout乘以这个factor

  • cluster-migration-barrier:迁移屏障,一个master最少要有多少个slave的数量,才允许数据迁移

  • cluster-require-full-coverage:集群需要全覆盖,故障后是否继续运行
  • cluster-replica-no-failover:集群副本无故障转移,此选项设置为yes时,可防止从设备尝试对其进行故障转移
  • cluster-allow-reads-when-down:是否允许集群在宕机时读取

附录五:使用命令脚本管理集群

Redis Cluster 在5.0之后取消了ruby脚本 redis-trib.rb 的支持,集成到redis-cli里,直接使用redis-clit的参数-- cluster 来取代
查看命令:redis-cli --cluster help

  • create:创建集群,如果指定slave数量,集群会根据redis实例自行划分,但是master和slave配对关系是自由组合的;一般不要指定slave数量,采用add-node方式添加节点,手动指定master和salve的对应关系
  • check:检查集群状态
  • info:查看集群信息
  • fix:修复或恢复集群
  • reshard:重分片,插槽迁移
  • rebalance:平衡集群节点插槽
  • add-node:集群中增加节点,可以指定master和slave对应关系,一般用在手动映射master和slave关系场景中
  • del-node:集群中删除节点
  • call:执行一些命令
  • set-timeout:设置超时时间,单位毫秒
  • import:导入数据到集群里来
  • backup:备份

AMQ简明教程(12)

hzqiuxm阅读(7371)

AMQ集群

Queue consumer clusters

ActiveMQ支持Consumer对消息高可靠性的负载平衡消费,如果一个Consumer死掉,该消息会转发到其它的Consumer消费的Queue上。
如果一个Consumer获得消息比其它Consumer快,那么他将获得更多的消息。
因此推荐ActiveMQ的Broker和Client使用failover://transport的方式来配置链接

Broker clusters

大部情况下是使用一系列的Broker和Client链接到一起。如果一个Broker死掉了,Client可以自动链接到其它Broker上。实现以上行为需要用failover协议作为Client。

如果启动了多个Broker,Client可以使用static discover或者 Dynamic discovery容易的从一个broker到另一个broker直接链接。

这样当一个broker上没有Consumer的话,那么它的消息不会被消费的,然而该broker会通过存储和转发的策略来把该消息发到其它broker上。

特别注意:ActiveMQ默认的两个broker,static链接后是单方向的,broker-A可以访问消费broker-B的消息,如果要支持双向通信,需要在netWorkConnector配置的时候,设置duplex=true 就可以了。

消息会较为平均的分配给2个集群,而不是每个消费者。即使某个消费者集群的消费者比其他集群中多,它获得的消息总数仍然差不多。不适合机器性能不均等的架构。

原因:networkConnector配置的可用属性conduitSubscriptions :默认true,标示是否把同一个broker的多个consumer当做一个来处理

负载均衡的时候一般设置为false, 设置为false后,会按照消费者个数来分配。

Master Slave

在5.9的版本里面,废除了Pure Master Slave的方式,目前支持:

1:Shared File System Master Slave:基于共享储存的Master-Slave:多个broker实例使用一个存储文件,谁拿到文件锁就是master,其他处于待启动状态,如果master挂掉了,某个抢到文件锁的slave变成master

2:JDBC Master Slave:基于JDBC的Master-Slave:使用同一个数据库,拿到LOCK表的写锁的broker成为master

3:Replicated LevelDB Store:基于ZooKeeper复制LevelDB存储的Master-Slave机制,这个是5.9新加的
具体的可以到官方察看: http://activemq.apache.org/masterslave.html

JDBC Master Slave的方式

利用数据库作为数据源,采用Master/Slave模式,其中在启动的时候Master首先获
得独有锁,其它Slaves Broker则等待获取独有锁。
推荐客户端使用Failover来链接Brokers。
具体如下图所示:

Master失败
如果Master失败,则它释放独有锁,其他Slaver则获取独有锁,其它Slaver立即获得独有锁后此时它将变成Master,并且启动所有的传输链接。同时,Client将停止链接之
前的Master和将会轮询链接到其他可以利用的Broker即新Master。如上中图所示

Master重启
任何时候去启动新的Broker,即作为新的Slave来加入集群,如上右图所示

JDBC Master Slave的配置

使用来配置消息的持久化,自动就会使用JDBC MasterSlave的方式。

Cucumber简明教程

hzqiuxm阅读(33181)

Cucumber简明教程

入门篇

简单介绍

  • 用途:BDD(行为驱动开发)自动化测试产品,可以和目前很多语言结合在一起。
  • 有明确的可执行规范,自动化测试,记录系统的实际行为

  • 特点:它使用自然语言来描述测试,使得非程序员可以理解他们
  • 官方安装地址:https://cucumber.io/docs/installation/
  • 依赖包:
dependencies {
    testCompile 'io.cucumber:cucumber-java8:4.3.1'
    testCompile 'io.cucumber:cucumber-junit:4.3.1'
    testCompile 'info.cukes: cucumber-java:1.2.5' //2016年之前的包
}
  • 如果你用的是IEAD可以检查是否自动安装了该插件:Cucumber for Java plugin,如果没有自己手动安装下

Gherkin语法部分

概念介绍

  • Feature:一个测试用例集
  • SCENARIOS:类似一个具体测试用例或场景
  • STEPS:测试步骤,每个SCENARIOS包含多个STEPS,STEPS可以使用如下关键词:Gievn,When,Then,But,And等
  • Given:创建测试环境需要的前提条件
  • When:触发某个业务事件
  • Then:验证事件产生的结果
  • And:多个前提条件时使用,连接前一个条件,作为正向条件
  • But:多个前提条件时使用,连接前一个条件,作为反向条件
  • Background:执行SCENARIOS之前会执行Bankground,在一个Feature里只能有一个,作用上有点SCENARIOS,作为公共的步骤
  • arguments:步骤中传入参数,支持单个参数和复杂参数datatable
  • SCENARIOS Outline:重复场景数据

基本原理

对国家语言支持

  • 支持40多种语言
  • https://github.com/cucumber/cucumber/blob/master/gherkin/gherkin-languages.json

几个feature文件的例子

  • 一个加减法的例子
Feature: Basic Add Test

  Background: give x and y value
    Given x and y value

  Scenario: Addition
    Given x is 4 and y is 5
    When invoke add Method
    Then the result is 9

  Scenario: autoX
    Given x is 1
    When invoke autoX Method
    Then the result is 2

  Scenario: Sub
    And sub operation
    When invoke calculate button
    Then the result is x-y
  • 一个复杂参数例子
Feature: Complex data type

  Scenario: multiple then keywords
    Given the user account infomation
    Then we can found user "hzqiuxm", with password "123456", phone "13989461462"
    Then we can found user "linjiangxian", with password "123456", phone "13989461462"
    Then we can found user "queqiaoxian", with password "123456", phone "13989461462"
  Scenario:
    Given use complex data
    Then 验证下面的一些用户账号信息
      | name    | password | phone |
      | hzqiuxm | 123456   | 13989461462 |
      | linjiangxian | 123456   | 13989461462 |
      | queqiaoxian | 123456   | 13989461462 |

  • 一个公共场景和中文支持的例子
Feature: With Scentrio Outline

  Background: 公共的登录操作
    Given 进行用户登录来测试Scentrio Outline

  Scenario Outline: 用户名或密码错误
    When 使用错误用户名 "<UserName>" 和密码 "<Password>" 来登录
    Then 不正确的用户名或密码

    Examples:
      | UserName | Password |
      | hzqiuxm  | 123321   |
      | simon    | 123321   |

  Scenario: 正确的用户名密码登录测试
    When 使用正确用户名 "hzqiuxm", 密码 "123456" 来登录
    Then 用户名密码正确,登录成功

操作步骤详情部分

Step Definitions

  • 不要定义重复的或模棱两可(正则匹配多个符合)的steps
  • 正则表达式的使用(参数要使用是小括号分组,字符串要用双引号)
  • 想多种情况下匹配又不想抓取参数时,使用?:正则表达式来进行说明
  • DataTable数据格式:dataTable类型,用户自定义类型(https://github.com/cucumber/cucumber/tree/master/datatable),list map类型,list list类型
  • DataTable的compare来做一些结果对比,用于CURD或其它操作结果的一些检测

Tagging

  • 可以按照标签来执行场景用例,使用"@"符号,例子:@v1.0.0 @hzqiuxm
  • 使用~ 取反,放在一个不同""里表示and关系,放在同一个""里表示or关系
tags = {"@v1.0.0","not @santai"}  //执行v1.0.0标签并且不包含santai标签的场景用例

Hooks

  • 类似Junit中的before,after作用,执行顺序:Before Hook, Background,Scenario,After Hook
  • @Before代表之前,@After代表之后
  • 多个Before后After可以使用Order属性值来控制,默认是按照代码中顺序来执行
  • Before和After可以结合tag属性,控制其作用范围,默认情况下是所有feature都有效的,tag属性也只是and和or的关系

Options

  • 作用在启动类上,用来控制测试报告report输出、plugin插件、标签Tag选择、环境配置、Feature文件选择、严格模式等
@CucumberOptions(plugin = {"pretty","json:target/cucumber-report3.json"},tags = {"@v1.0.0","~@santai"})
  • Feature:只执行指定路径下的feature
  • gule:指定feature对应的测试类路径
  • tags:指定执行的标签规范
  • dryRun:不会真正的去执行steps,但会检查哪个feature没被实现
  • strict:严格模式下出现未实现的steps或断言失败就会失败报错
  • monochrome:影响控制台输出的样式效果
  • 支持的输出格式:html:target/Cucumber;json:target_json/Cucumber.json;junit:target_json/Cucumber_junit.xml

第三方整合

  • Jenkins整合,在Jenkins中安装cucumber 插件

自动构建后就会生产相关的报告

  • 结合Assured进行RESTful API测试
http://rest-assured.io/

https://www.baeldung.com/rest-assured-tutorial/

  • 结合selenium进行自动化测试
// https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java
compile group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '3.14.0'

几个gradle下的cucumber插件

  • https://github.com/samueltbrown/gradle-cucumber-plugin
  • https://plugins.gradle.org/plugin/se.thinkcode.cucumber-runner
  • https://plugins.gradle.org/plugin/com.github.spacialcircumstances.gradle-cucumber-reporting
  • https://github.com/awbdallas/gradle-cucumber-jvm-plugin

个人总结

  • cucumber是敏捷开发团队常用的一种测试框架,它鼓励了系统开发环节中各个参与者来进行协作,其中也包括非技术人员
  • cucumber中的测试场景一般由纯自然语言来进行描述,很易懂,因此,非技术人员也可以来编写测试用例,然后通过技术人员来进行实现它。
  • Cucumber可以让人们用近似自然的语言去描述Feature和场景,根据Feature驱动开发。用作软件技术人员和非技术之间验收测试的桥梁。
  • 如果刚开始践行BDD,通常最好让开发人员编写
  • 如果只是用作测试自动化工具,可以由测试人员和开发人员编写
  • 特性(Feature)文件应该描述特性,而不是应用程序的组成部分,每个特性文件应有一个好的命名,并保持特性的专注
  • 避免特性与领域逻辑的不一致性,确保使用客户的领域语言。这一活动的最佳做法是让客户也参与编写故事。
  • 用组织代码的思想来组织你的特性与场景(Scenary)
  • 灵活使用标签Tag
  • 您的方案应该描述系统的预期行为,而不是实现。换句话说,它应该描述什么,而不是如何描述

欢迎加入极客江湖

进入江湖关于作者