• [活动公告] 【华为云社区内容共创者火热招募中】第五弹:拒绝躺平,踮脚够上生活小美好!看直播写博客,更有价值高达500元京东卡可领取!
    随着躺平文化的迅速蹿红,引发了许多年轻人的共鸣,很多人也随即选择躺下。然则,生活可能是平凡而琐碎的,却总有值得我们站起来,踮脚够一够的小美好。在感慨完“人间不值得”后,继续“扑腾”在时代的浪潮中。所以,现在让我们一起加入华为云社区,继续前进吧!华为云社区“内容共创计划”第五弹!!计划关键词:免费学习大厂资料,提升内容编辑能力,整理输出沉淀思考,赢取更多精彩奖励!一举多得,何乐不为?无论你是正在读书的学生开发者,还是经验丰富的职场技术人,都非常适合这个计划!华为云社区将不定期发布内容共创任务;报名者通过审核后将被分配任务;完成任务获取相应奖励!01.任务介绍文章编辑整理类:针对音视频、PDF等文件进行文章整理,准确度高,体现技术重点,形成可读性较强的文章,图文结合,标题具有吸引力,字数根据实际文件内容进行要求。专题内容整理类:将华为云社区优质内容按照专题类别编辑整理成册,形成合集。内容翻译类:针对海外优质内容进行翻译整理,准确度高,可读性强。其他更多任务不定期更新。02.奖励根据文章字数、文章质量、文章阅读量等主要指标,华为云社区编辑部进行综合考核,给予奖励.奖励金额:100~300元/篇,如连续2期都得到满分,则额外奖励200元,(以京东卡或等值社区礼品形式进行发放)。第五弹任务火热来袭,优秀的你准备好接招了吗?点此立即报名03.任务领取第一波任务:将以下20个专家直播视频内容编辑整理成为技术文章,每个任务仅限由1人完成,每人报名时可选取1个任务,若审核通过,工作人员将与您私信联系进行任务分配。序号观看直播任务1工商银行:基于Karmada千级容器集群的业务容灾管理设计任务2VIPKID:在线教育平台跨云迁移从天到秒的实践任务3AIOps园区网络运维实践及应用任务4天级开发,周级上线: RPA助力企业快速实现流程自动化(国内)任务5IoT高可靠架构演进之单元化(国内)任务6鹏城论剑,共话数据库前沿技术和趋势任务7如何使用openGauss NUMA技术,实现金融核心数据库性能提升30%(国内)任务8视觉计算预训练大模型,加速迈向通用人工智能任务9知识计算如何让新冠药物筛选效率提升70%?任务10AI行业应用的前端全景UI低代码开发任务11如何只用一小时定制一个行业AI模型?任务12以多学科在线会诊为例,看下一代远程协同应用(国内)任务13如何构建全无线物联园区,让物联终端一触即联(国内)任务14EdgeGallery,让5G能力在边缘触手可及(国内)任务15支撑华为20万员工的IT运营与服务体系实践(国内)任务16分布式存储容量提升35%的黑科技:鲲鹏BoostKit KPS ZIP压缩算法(国内)任务17领先开源软件10%+性能的鲲鹏加速库技术详解(国内)任务18如何在开源社区提交第一行代码(国内)任务191/10 代码,1/6 时间,如何基于MindX快速开发一个商业AI应用(国内)任务20基于MindSpore 如何实现千亿参数GPT-3自动并行训练04.文章整理要求:文章内容需准确度高,体现技术重点,形成可读性较强的文章,请不要单纯的复制粘贴材料里的内容,文章字数不少于2000字,以Word文档形式输出。1、文字精练:通过严谨和专业的文字进行文章整理,不可直接复制速记内容,无错别字;2、思路清晰:整篇文章逻辑清晰,观点输出准确,语句通顺;3、结构工整:结构分明,排版工整,文中需要用小标题进行分割(不能单纯是数字);4、图文并茂:“一图胜千言”,能够在文中准确的配图,让文章内容更加丰富;5、引人入胜:文章标题、内容具有吸引力,抓人眼球,文采好,为加分项。05 参考案例:1、 从GaussDB(for MySQL)看全自研数据库的正确打开方式视频链接:https://bbs.huaweicloud.com/videos/103466文章链接:https://bbs.huaweicloud.com/blogs/1998912、开发者如何抓住时代机遇,学好AI?视频链接:https://bbs.huaweicloud.com/videos/103459文章链接:https://bbs.huaweicloud.com/blogs/19988906.报名方式点此立即报名名额有限,先到先得!报名成功后,工作人员将在2个工作日内进行审核,通过审核后工作人员将与您私信联系进行任务分配。07.交稿时间2021年7月9日之前如有任何问题,可添加华为云小助手蛋花微信号:Huawei-danhua,进行沟通咨询。添加微信时请务必备注:内容共创+报名活动时使用的华为云昵称。生活可能是平凡而琐碎的,却总有值得我们站起来,踮脚够一够的小美好。现在就让我们一起加入华为云社区,继续前进吧!
  • [热门活动] 2021华为云GaussDB挑战赛推荐好友来报名,Mate40 Pro触手可得
    #2021华为云GaussDB挑战赛,代码筑城,无所不能#,推荐好友来报名,即可获得超值惊喜礼品!,除了有跑步机、华为WATCH GT 2e、机械键盘等,更有超级大奖Mate40 Pro让你触手可得,你还在等什么呢?赶紧行动起来,实物奖品数量有限,先到先得喔!具体详情活动请戳:https://competition.huaweicloud.com/information/1000041405/introduction
  • [热门活动] HDC.Cloud2021 |鹏城论剑,还看今朝,华为云数据库峰会直播即将开始!
    相约鹏城,看大咖论剑数据库前沿技术和趋势分享抢先看4月25日14:00-16:00围观现场直播,get大会精华!
  • [热门活动] HDC.Cloud2021 |高校开发者必看,面试官心中的最佳数据库人才模型是什么样?
    2021年4月24日HDC.Cloud2021华为开发者大会在深圳大学城火热开启众多行业大咖与开发者一同共赴盛会无法到现场的开发者们速来集合啦!华为云数据库将通过直播为高校开发者带来人才发展的三大秘笈想知道数据库学科提升之路吗?想知道企业需求的数据库人才模型吗?想知道HR面试的核心关注点吗?4月24日13:30-16:20锁定直播间精彩干货享不停!
  • [技术干货] 常用设计模式
    ### 设计与模式之前一直以为「设计模式」是一个完整的名词其实「设计」和「模式」是要分开来说的**「设计」:5 个常见的设计原则****「模式」:代码中常见的"套路",被程序员总结成了相对固定的写法,称之为「模式」**也就是说学习"设计模式",首先肯定要学习和理解 5 个设计原则。#### 五大设计原则-SOLID- S(single)-单一职责原则- 一个程序只做好一件事;如果功能过于复杂就拆分开,每个部分保持独立;- O(open-close)-开放封闭原则- 对扩展开放,对修改封闭;增加需求时,扩展新代码,而非修改已有代码;- L(Liskov)-里氏置换原则-子类能覆盖父类;父类能出现的地方子类就能出现;- I(Interface)-接口独立原则-保持接口的单一独立,避免出现”胖接口“;js中没有接口(typescript除外),使用少;- D(Dependence)-依赖倒置原则-编程依赖抽象接口,不要依赖具体实现;使用方只关注接口而不关注具体类的实现;**示例 promise**- 单一职责原则:每个 then 中的逻辑制作好一件事- 开放封闭原则:如果新增需求,扩展 then```js// 0.0.1/loadImg.jsfunction loadImg(src) { let promise = new Promise(function (resolve, reject) { let img = document.createElement('img'); img.onload = function () { resolve(img); } img.onerror = function () { reject('图片加载失败'); } img.src = src; }); return promise;}let imgUrl = 'https://raw.githubusercontent.com/ruizhengyun/images/master/cover/ruizhengyun.cn_.png';loadImg(imgUrl).then(function (img) { console.log(`width: ${img.width}`); return img;}).then(function (img) { console.log(`height: ${img.height}`);}).catch(function (ex) { console.log(ex);});```#### Javascript 常用设计模式 -- 工厂模式工厂模式也称创建模式,是用于创建对象的一种方式。可以说就是用来代替 new 实例化对象,决定了实例化哪一个类,从而解决解耦问题。**拟物化解读**一个工厂接到一笔订单(传参),然后根据这个订单类型(参数)来安排产品线(实例化哪个类),当然客户可以要求一些产品的工艺属性(抽象工厂)。这其中厂长(工厂模式)只负责调度,即安排产品零件流水线。你应该知道的是,工厂有个特点就是产出体量大、相似度高的产品。如果你要做单一定制化的产品,那这笔订单给工厂就不适用了。**其作用(利)**解耦,通过使用工程方法而不是 new 关键字;将所有实例化的代码集中在一个位置减少代码重复,降低出错;**具体实现**分步创建一个复杂的对象,解耦封装过程和具体创建组件(分解为零件流水线);无需关心组件如何组装(厂长在调度);不暴露创建对象的具体逻辑,将逻辑封装在一个函数中(客户只需要告诉工厂做什么和提一些要求);**适用场景**处理大量具有相同属性的小对象;对象的构建十分复杂,需要依赖具体环境创建不同实例**分类(抽象程度)**不暴露创建对象的具体逻辑,而是将逻辑封装在一个函数中,那么这个函数就可以被视为一个工厂。##### 简单工厂模式也可以叫静态工厂模式,用一个工厂对象创建同一类对象类的实例。现实生活中,用户在平台还是分等级的,角色不同,权限也不同。**1.ES5 实现**```js// 0.0.2/es5.simple.factory.jsfunction Role(options){ this.role = options.role; this.permissions = options.permissions;}Role.prototype.show = function (){ var str = '是一个' + this.role + ', 权限:' + this.permissions.join(', '); console.log(str)}function simpleFactory(role){ switch(role) { case 'admin': return new Role({ role: '管理员', permissions: ['设置', '删除', '新增', '创建', '开发', '推送', '提问', '评论'] }); break; case 'developer': return new Role({ role: '开发者', permissions: ['开发', '推送', '提问', '评论'] }); break; default: throw new Error('参数只能为 admin 或 developer'); }}// 实例const xm = simpleFactory('admin');xm.show();const xh = simpleFactory('developer');xh.show();const xl = simpleFactory('guest');xl.show();```**2.ES6 实现**```js// 0.0.2/simple.factory.jsclass SimpleFactory { constructor(opt) { this.role = opt.role; this.permissions = opt.permissions; } // 静态方法 static create(role) { switch (role) { case 'admin': return new SimpleFactory({ role: '管理员', permissions: ['设置', '删除', '新增', '创建', '开发', '推送', '提问', '评论'] }); break; case 'developer': return new SimpleFactory({ role: '开发者', permissions: ['开发', '推送', '提问', '评论'] }); break; default: throw new Error('参数只能为 admin 或 developer'); } } show() { const str = `是一个${this.role}, 权限:${this.permissions.join(', ')}`; console.log(str); }}// 实例const xm = SampleFactory.create('admin');xm.show();const xh = SampleFactory.create('developer');xh.show();const xl = SampleFactory.create('guest');xl.show();```或```js// 0.0.2/simple.factory2.jsclass Role { constructor(options) { this.role = options.role; this.permissions = options.permissions; } show() { const str = `是一个${this.role}, 权限:${this.permissions.join(', ')}`; console.log(str); }}class SimpleFactory { constructor(role) { if(typeof this[role] !== 'function') { throw new Error('参数只能为 admin 或 developer'); } return this[role](); } admin() { return new Role({ role: '管理员', permissions: ['设置', '删除', '新增', '创建', '开发', '推送', '提问', '评论'] }); } developer() { return new Role({ role: '开发者', permissions: ['开发', '推送', '提问', '评论'] }); }}// 实例const xm = new SimpleFactory('admin');xm.show();const xh = new SimpleFactory('developer');xh.show();const xl = new SimpleFactory('guest');xl.show();``` 上例中,simpleFactory 就是一个简单工厂,2个实例对应不同的权限,调用工厂函数时,只需传递 admin 或 developer 就可获取对应的实例对象。**1.简单工厂函数适用场景**正确传参,就可以获取所需要的对象,无需知道内部实现细节;内部逻辑(工厂函数)通过传入参数判断实例化是使用哪些类;创建对象数量少(稳定),对象的创建逻辑不复杂;**2.简单工厂函数不适用场景**当需要添加新的类时,就需要修改工厂方法,这违背了开放封闭原则(OCP, 对扩展开放、对源码修改封闭)。函数 create 内包含了所有创建对象(构造函数)的判断逻辑代码,如果要增加新的构造函数还需要修改函数 create(判断逻辑代码),当可选参数 role 变得更多时,那函数 create 的判断逻辑代码就变得臃肿起来,难以维护。不适用创建多类对象;##### 工厂方法模式将实际创建对象工作推迟到子类当中,核心类就成了抽象类。这样添加新的类时就无需修改工厂方法,只需要将子类注册进工厂方法的原型对象中即可。**1.ES5 实现**,ES5 没有像传统创建类的方式那样创建抽象类,所以工厂方法模式只需参考其核心思想即可。可将工厂方法看做一个实例化对象工厂类(采用安全模式类),将创建对象的基类放在工厂方法类的原型中即可。当需要添加新类时,只需挂载在 FunctionFactory.prototype 上,无需修改工厂方法,也实现了 OCP 原则。```js// 0.0.2/es5.function.factory.jsfunction FunctionFactory(role) { if(!(['admin', 'developer'].indexOf(role) > -1)){ throw new Error('参数只能为 admin 或 developer'); } // 安全的工厂方法 if (this instanceof FunctionFactory) { return this[role](); } return new FunctionFactory(role);}FunctionFactory.prototype.show = function () { var str = '是一个' + this.role + ', 权限:' + this.permissions.join(', '); console.log(str)}FunctionFactory.prototype.admin = function (permissions) { this.role = '管理员'; this.permissions = ['设置', '删除', '新增', '创建', '开发', '推送', '提问', '评论'];}FunctionFactory.prototype.developer = function (permissions) { this.role = '开发者'; this.permissions = ['开发', '推送', '提问', '评论'];}var xm = FunctionFactory('admin');xm.show();var xh = new FunctionFactory('developer');xh.show();var xl = new FunctionFactory('guest');xl.show();```**2.ES6 实现**,由于 ES6 中还没有 abstract,就用 new.target 来模拟出抽象类(new.target 指向被 new 执行的构造函数),判断 new.target 是否指向了抽象类,如果是就报错。```js// 0.0.2/function.factory.jsclass FunctionFactoryBase { // 抽象类 constructor(role) { if (new.target === FunctionFactoryBase) { throw new Error('抽象类不能实例'); } this.role = role; }}class FunctionFactory extends FunctionFactoryBase { // 子类 constructor(role) { super(role); } static create(role) { switch (role) { case 'admin': return new FunctionFactory({ role: '管理员', permissions: ['设置', '删除', '新增', '创建', '开发', '推送', '提问', '评论'] }); break; case 'developer': return new FunctionFactory({ role: '开发者', permissions: ['开发', '推送', '提问', '评论'] }); break; default: throw new Error('参数只能为 admin 或 developer'); } } show() { const { role, permissions } = this.role; const str = `是一个${role}, 权限:${permissions.join(', ')}`; console.log(str) }}// let xl = new FunctionFactoryBase(); // 此行会报错,注释后方可正常执行后面let xm = FunctionFactory.create('admin');xm.show()let xh = FunctionFactory.create('developer');xh.show()let xl = FunctionFactory.create('guest');xl.show()```##### 抽象工厂模式抽象工厂只留对外的口子,不做事,留给外界覆盖(子类重写接口方法以便创建的时候指定自己的对象类型)。主要用于对产品类簇的创建,不直接生成实例(简单工厂模式和工厂方法模式都是生成实例)。- 抽象类是一种声明但不能使用的类,子类必须先实现其方法才能调用;- 可以在抽象类中定义一套规范,供子类去继承实现;```js// 0.0.2/abstract.factory2.js// 抽象工厂function AbstractFactory(subType, superType) { if (typeof AbstractFactory[superType] === 'function') { //缓存类 function F() { } //继承父类属性和方法 F.prototype = new AbstractFactory[superType](); //将子类 constructor 指向子类(自己) subType.prototype.constructor = subType; //子类原型继承缓存类(父类) subType.prototype = new F(); } else { //不存在该抽象类抛出错误 throw new Error('抽象类不存在') }}// 抽象类AbstractFactory.Phone = function () { this.type = 'Phone';}AbstractFactory.Phone.prototype = { showType: function () { return new Error('Phone 抽象方法 showType 不能调用'); }, showPrice: function () { return new Error('Phone 抽象方法 showPrice 不能调用'); }, showColor: function () { return new Error('Phone 抽象方法 showColor 不能调用'); }}AbstractFactory.Pad = function () { this.type = 'Pad';}AbstractFactory.Pad.prototype = { showType: function () { return new Error('Pad 抽象方法 showType 不能调用'); }, showPrice: function () { return new Error('Pad 抽象方法 showPrice 不能调用'); }, showColor: function () { return new Error('Pad 抽象方法 showColor 不能调用'); }}// 抽象工厂实现对抽象类的继承function Iphone(type, price, color) { this.type = type; this.price = price; this.color = color;}//抽象工厂实现对 Phone 抽象类的继承AbstractFactory(Iphone, 'Phone');Iphone.prototype.showType = function () { return this.type;}Iphone.prototype.showPrice = function () { return this.price;}Iphone.prototype.showColor = function () { return this.color;}function Ipad(type, price, color) { this.type = type; this.price = price; this.color = color;}AbstractFactory(Ipad, 'Pad');Ipad.prototype.showType = function () { return this.type;}Ipad.prototype.showPrice = function () { return this.price;}Ipad.prototype.showColor = function () { return this.color;}// 实例var iphone5s = new Iphone('iphone 5s', 3000, '白色');console.log('今天刚买了' + iphone5s.showType() + ',价格是' + iphone5s.showPrice() + ',' + iphone5s.showColor())var iphone8s = new Iphone('iphone 8s', 8000, '白色');console.log('今天刚买了' + iphone8s.showType() + ',价格是' + iphone8s.showPrice() + ',' + iphone8s.showColor())var ipad = new Ipad('ipad air', 2000, '骚红色');console.log('今天刚买了' + ipad.showType() + ',价格是' + ipad.showPrice() + ',' + ipad.showColor())```**除此之外还有单例模式、适配器模式、装饰器模式、代理模式、观察者模式、迭代器模式等**
  • [网站建设] 吉佳通达——专业的定制软件开发商
    吉佳通达作为专业的定制软件开发商,一直秉承为政府和企业信息化建设提供先进技术、成熟产品和优质服务为目标。凭借多年来为行业客户提供定制、开发、维护服务的经验,建立了一套完整的软件定制开发服务规范及流程。吉佳通达软件定制化开发遵循的项目开发管理流程:根据用户的要求进行需求调研、进行软件设计,提供新建系统的方案设想,并进行可行性分析;在开发过程严格遵循开发管理规范:在程序编码前进行系统的概要设计和详细设计;在程序编制结束后进行软件测试、项目交付、对用户有关人员进行操作培训,并提供软件正常运行后常规维护。公司根据定制软件开发项目特点,建立了符合CMMI2.0三级的标准化软件开发规范,使项目开发过程更加具有稳定性和可控性;通过建立项目管理流程,形成一个有机的整体,实现软件开发时间、成本和功能可跟踪和可控制,保证产品的质量。成熟的软件开发框架软件开发框架就如同是软件开发系统的地基, 属于软件开发系统核心因素,对于一个系统所存在的基本功能、宏观特性、主体结构起到决定性的作用。当定制项目实施的时候,如果没有一个完整架构,会导致接口不统一、业务逻辑接口多样、代码混乱,整体开发效率也会相应降低,后期维护相对繁琐。吉佳通达软件定制开发采用基于VUE的先进的、成熟的软件开发框架。基于此框架创建可维护性和可测试性更强的代码库,为客户带来更加丰富的交互体验;为企业和客户降低成本,提高项目质量;改善客户满意程度、控制开发进度等。同时采用基于VUE的开发框架可将相关技术以代码、文档、模型等方式固化下来,便于项目二次开发及升级。专业的技术团队公司核心团队由具备10年以上资深高级系统分析师、高级软件架构师、软件设计师等人员组成,根据业务的需求合理调配人员,保障开发效率最大化,提高客户满意度。技术开发团队包括:前端开发、后台开发、算法分析与建模,JAVA开发组、C++开发组、Python开发组、移动开发组、VUE框架、测试组和系统集成组,团队人员分工明确;设计、产品和运营构成后端支撑,对接客户的需要,进行前期的业务沟通、项目跟进、后期的运营指导和维护。14年行业定制开发典型案例 吉佳通达凭借完善、成熟的管理和开发流程,确保为客户提供高质量的服务和专业定制化产品;遵循严格的安全标准,实施严密的安全措施,以保护客户的信息安全;公司的综合实力是帮助客户建立成熟可靠、切实可用的定制应用的基础、是提供最专业定制开发服务的坚实保障。
  • [技术干货] 华为云PB级数据库GaussDB(for Redis)揭秘第二期:Redis消息队列Stream的应用探讨
    引言:Redis Stream是Redis 5.0引入的一种新的数据类型,其本质是一个消息队列,类似于 kafka等消息中间件。它提供了消息的落地存储功能,并实现了类似kafka消费组和消费者的功能。与kafka相比,Redis Stream同样拥有强大的功能,但因原生Redis无法有效支持大规模数据存储,成本昂贵,并存在数据丢失/不一致风险等原因,导致其未能流行起来。本文将对Stream的常用命令和应用场景进行介绍,并探讨原生Redis Stream消息队列的缺陷以及GaussDB(for Redis)提供的解决方案,供大家学习和选用。一、Redis Stream简介与Pub/Sub相比,Redis Stream 具有消息的落地存储功能,每一个客户端能访问任意时刻的消息,并且能记录每一个客户端的访问位置,还能保证消息不会丢失。Redis Stream 的结构如下所示,它有一个消息链表,将所有加入的消息都链接起来,每个消息都有唯一的 ID 和对应的内容。如图所示,每一个Stream队列包含多条消息,每条消息由唯一的ID进行标识,由时间戳和序列号组成,例如1627849609889-0。每条消息以追加的方式添加到Stream队列中。同一个Stream队列可以包含多个消费组(Consumer Group),每个消费组的状态都是独立的,同一个Stream队列的消息可以被多个消费组重复消费。同一个消费组又包含多个消费者(Consumer),这些消费者之间是竞争关系,不同消费者不会重复消费同一条消息,任意一个消费者读取了队列中的一条消息都会使消费组中的游标last_delivered_id往前移动。该方式提高了并发效率,例如,多个进程并发处理Stream队列中的消息。每个消费者中维持一个状态变量pending_ids,简称为PEL(Pending Entries List),记录了当前已经被客户端读取的但尚未被ACK的消息,确保消息被客户端成功消费。Redis Stream命令可以分为消息队列命令和消费者命令两类,如下所示:以即时通讯中的聊天室场景为例,使用Redis Stream作为中间件,实现聊天室的发言以及信息查看。使用XADD命令进行发言使用XLEN命令获取聊天室发言的数量使用XRANGE获取消息队列的消息使用XREAD命令读取消息。可以在不设置消费组和消费者的情况下,使用XREAD的命令进行消息读取,此时Stream队列类似于一个普通的列表(list)。更多的Redis Stream命令使用请参考官方文档(https://redis.io/commands/xread)。二、应用场景由于Redis Stream天然有序,特别适合存储时序数据,应用场景包括即时通讯、智慧医疗、流量削峰、智慧城市等领域。(1)即时通讯:微信、QQ等是我们日常生活中常用的通讯软件,常用的聊天方式包含点对点通讯和群聊两种方式。下图是一个群聊的模型图,当采用Redis Stream作为通讯的中间件,创建一个群聊时,在Redis中对应地为该群聊创建一个Stream队列。在发送消息时,将每个用户的消息按照时间顺序添加到Stream队列中,保证了消息的有序性。由于Stream是一个持久化的队列,无论是在线还是离线状态,每个用户可以多次查看历史消息,保证了通讯的完整性。(2)智慧医疗:医疗行业的信息化,可以更好地为服务于每一个人。为每一个人从出生起建立一份健康档案,记录相应的健康信息,如体检报告、诊断报告、用药信息、以及智能终端实时上传的健康指标。这些信息都是一些时序数据,同样可以采用Redis Stream来实现智慧医疗系统。建立起智慧医疗系统后,使用终端可以查看所有的医疗信息,并会提示患者按时吃药,在终端上传身体指标异常时,会自动报警并预约挂号。现阶段每个医院都有自己的信息系统,不同的医院很难查到同一个患者的医疗信息,在未来,医疗上云将有利于解决医疗信息孤岛,更好的帮助每一位患者。(3)流量削峰:在常见的秒杀活动或团购中,如春运抢票、商城促销等,通常短时间内有大量的流量,导致系统崩溃。由于每一个用户在请求时对应唯一的时间戳,所有的请求都有一个先后顺序,同样可以采用Redis Stream作为中间件,将请求加入到Redis Stream消息队列。将消息转存到消息队列间接提供给应用,而非直接发送给应用,可以防止大流量冲击导致的系统崩溃。当消息队列中的请求数量达到规定的最大值时,直接回复客户端抢购失败。三、原生Redis是否真的适用于以上场景?如上应用场景具有数据规模大、数据持续增长的特点,虽然原生Redis有良好的设计初衷,但是并不能解决实际问题。具体体现在:无法有效应对大规模数据:原生Redis是一个基于内存的数据库,单个节点存储容量有限,当扩展至TB级别的集群,将会出现管理困难,运维成本高等问题。集群扩容影响业务性能:原生Redis在进行集群扩容时,需要重新划分hash槽并进行数据迁移,必定会影响业务性能。数据可能会丢失:原生Redis虽然可以采用RDB和AOF的方式对数据进行持久化,但是并不会实时地将每一条命令写入到硬盘中,当出现掉电或集群崩溃的情况,必定会丢失一部分数据,对于类似智慧医疗场景,是难以忍受的。除此以外,必须考虑数据库系统的可用性、数据一致性、成本和备份恢复能力等情况:可用性: 原生Redis若采用一主一备的集群模式,当一对主备节点下线,集群部分数据将不可用。数据一致性:当主节点宕机,主备节点切换,数据存在没有完全同步的情况。成本:原生Redis是一种内存型数据库,当内存容量扩展至TB级别,成本将非常昂贵。备份恢复:需要人工连接数据库执行 SAVE或BGSAVE命令,不能支持定期自动备份,在恢复到新实例时需要手动拷贝备份数据。四、是否有更好的解决方案?在以上场景中,亟需一种能够存储和处理大规模Stream数据、鲁棒性强、且成本低廉的数据库系统。而GaussDB(for Redis)(下文简称高斯Redis)正是以上场景中一种很好的应用解决方案。高斯Redis是华为云数据库团队自主研发的兼容Redis协议的云原生数据库,该数据库突破原生Redis的内存限制,可轻松扩展至PB级存储,具有秒扩容、超可用、强一致和低成本等特点。五、总结Redis Stream可以广泛应用在即时通讯、智慧医疗、流量削峰等领域。在面对大规模的Stream数据时,原生Redis存在成本过高、容量太小、可用性差、数据不一致等问题,无法适用于海量消息队列的场景。与原生Redis相比,高斯Redis具有海量存储,低成本,可持久化等优点,可做为比原生Redis更理想的Stream队列承载方案。
  • [技术干货] 前端调试机器
    ## Chrome调试工具!(https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/forums/attachment/forum/202102/25/1946416mxtydgfysrjdlpr.png)#### 箭头 & Elements##### **箭头:** 用于在页面选择一个元素来审查和查看它的相关信息。##### Elements 内容: + 样式!(https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/forums/attachment/forum/202102/25/194757x6mhhgmwz9gbreas.png)+ 计算属性!(https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/forums/attachment/forum/202102/25/194818ubcs8xiddehihlld.png)+ 事件监听> 将Ancestors和Framework Listeners两个checkbox取消选中可以看到 选择dom绑定的事件。 !(https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/forums/attachment/forum/202102/25/19485498syfy4vrdtswdyu.png)+ DOM breakpoints + 在Chrome开发者工具里,选中想要监控的DOM元素,点击右键,选择Break on->Attributes modifications: !(https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/forums/attachment/forum/202102/25/194930vyblmcvnviuv0ibv.png) + 之后在DOM Breakpoints的tab里能看到对应的断点 + 然后回到Chrome里鼠标悬停百度一下,Chrome开发者工具的调试器就会自动在DOM的属性发生变化的地方停下来: !(https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/forums/attachment/forum/202102/25/195014m4pmhursabbfcgvl.png) + 从调试器的调用上下文能了解到是上图第118行的className 改变了导致DOM断点的触发。+ Properties> 改选项卡里面可以看到 选择dom对象,及类的继承链。!(https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/forums/attachment/forum/202102/25/195235nmhgfm2ud8xqqlaa.png)#### 设备模拟器> 模拟移动屏幕,或者一些其它的像素比例的屏幕。!(https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/forums/attachment/forum/202102/25/195301vmhsnbu9oek0zngc.png)#### Console控制台> 控制台打印, 执行脚本。!(https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/forums/attachment/forum/202102/25/195332g2eidbbtv36dtdyn.png)#### Sources!(https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/forums/attachment/forum/202102/25/195348qeupdyr3bfddtzvq.png)#### NetWork!(https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/forums/attachment/forum/202102/25/195402wvgl1f8vwx0fcpou.png)#### Performance!(https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/forums/attachment/forum/202102/25/195415ap0bhda0beswf2qf.png)#### Memory: 内存快照!(https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/forums/attachment/forum/202102/25/1954370qptqahc0icxkxly.png)## Vscode内代码调试#### 调试环境配置> 在.vscode / launch.json 文件夹为配置文件。(可以快捷键ctrl + p 然后输入 debug 进行快速配置)!(https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/forums/attachment/forum/202102/25/195510wrw7ka6vzelhpqth.png)**参数说明:**```json"name": "Attach to Chrome", // 调试环境名称"type": "pwa-chrome", //调试环境运行环境, 取值: node pwa-chrome 或其它自行安装的程序命令"request": "attach" | "launch", // attach模式: 监听一个启动进程 launch模式: 由vscode 来启动一个独立的debug进程 "url": "http://localhost:8080", // 服务地址 launch模式才会有"port": 9222, // 端口 attach才会有"webRoot": "${workspaceFolder}" // 静态资源目录"cwd": "${workspaceFolder}/dist", // 指定程序启动调试的目录 ,当vscode启动目录不是项目根目录,并且调试npm script时非常有用"args": ["--no-install"],"outFiles": ["${workspaceFolder}/lib/**/*.js"], //指定 sourceMaps的位置"skipFiles": [ "<node_internals>/**/*.js", "${workspaceFolder}/node_modules/**/*.js" ], //指定跳过单步调试的代码"preLaunchTask": "npm: build", // launch之前做的事情"stopOnEntry": true, //自动断点到第一行代码处"smartStep": true, //自动跳过未映射到源代码的代码```#### 单个JS调试> 添加如下配置到launch.json 选择test.js F5 debug模式运行```json{ "type": "node", "request": "launch", "name": "debug test", "runtimeExecutable": "node", "program": "${workspaceFolder}/code/debugger/test.js", "restart": true, "console": "integratedTerminal", "internalConsoleOptions": "neverOpen" }```#### 项目调试+ 安装插件:`Debugger for Chrome`!(https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/forums/attachment/forum/202102/25/195956i5k2fllzldgodgyh.png)+ 配置launch.json```json{ "type": "chrome", "request": "launch", "name": "launch project dbug", "url": "http://localhost:8993/drs", "webRoot": "${workspaceFolder}", "preLaunchTask": "debug", "sourceMapPathOverrides": { "webpack://[name]/./*": "${webRoot}/*", "webpack:///src/*": "${webRoot}/*", "webpack:///*": "*", "webpack:///./~/*": "${webRoot}/node_modules/*", }, },```+ 配置debug命令```json{ "version": "2.0.0", "command": "npm", // 运行命令的程序 "tasks": [ { "label": "debug", // Task 名称 "isBackground": true, "type": "npm", "script": "start", // npm 要执行的 script 名称,对应 package.json 中的定义 "detail": "编译至开发环境", // Task 的描述,在命令面板中显示 "group": "test", "problemMatcher": { "fileLocation": "relative", "pattern": { "regexp": "^([^\\s].*)\\((\\d+|\\,\\d+|\\d+,\\d+,\\d+,\\d+)\\):\\s+(error|warning|info)\\s+(TS\\d+)\\s*:\\s*(.*)$", "file": 1, "location": 2, "severity": 3, "code": 4, "message": 5 }, "background": { "activeOnStart": true, "beginsPattern": ".", "endsPattern": "Version: webpack.+" } } } ]}```+ 运行`launch project dbug` 命令
  • [技术干货] 前端模块规范简介
    模块化的好处:避免命名冲突(减少命名空间污染)更好的分离, 按需加载更高复用性高可维护性1.CommonJSNode.js 应用由模块组成,采用 CommonJS 模块规范。 1.1 语法风格//Math.jsmodule.exports = {    'add': function(a, b) { return a + b;    }}//main.jsconst Math = require('./Math');console.log(Math.add(2, 3));console.log('done');/**输出:-->node main5done**/1.2 同步加载由上面例子可以看出,CommonJS中模块是同步加载的1.3 动态加载//main.jsconst Math = require('./Ma' + 'th');//动态拼接CommonJS支持动态加载模块。因为conmonJs是同步的,执行到这一行时,才会加载模块。1.4 浏览器不支持CommonJS规范。浏览器不兼容CommonJS的根本原因,在于缺少四个Node.js环境的变量。moduleexportsrequireglobal可以使用工具进行转换,例如:Browserify1.5 其他特点所有代码都运行在模块作用域,不会污染全局作用域。模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。模块加载的顺序,按照其在代码中出现的顺序。CommonJS模块的加载机制中,输入的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。适合服务器端小测验//Math.jslet counter = 1;let addCounter = function () {    counter++;};module.exports = {    counter,    addCounter};console.log('Math init');//main.jsconst Math = require('./Math');Math.addCounter();console.log(Math.counter); // position AMath.counter = 5;const Math2 = require('./Math');console.log(Math2.counter); // position B//位置A 和 位置B的值分别是什么?2.AMDCommonJS是主要为了JS在后端的表现制定的,他是不适合前端的。AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义"。RequireJS实现了AMD规范。下面以RequireJS为例,了解一下AMD规范。2.1 语法风格//Math.jsdefine([], function(){    return {        'add': function(a, b) { return a + b; }    }})//main.jsrequire.config({    paths : {        "math" : "Math"    }});require(['math'], function (math) { console.log(math.add(2, 3));});console.log('done');//done//52.2 异步加载由上面的例子可以看出,require命令是异步执行的2.3 动态加载2.4 依赖前置,提前执行3.CMD(Common Module Definition)CMD是SeaJS 在推广过程中对模块定义的规范化产出。CMD规范和 AMD 很相似,尽量保持简单,并与 CommonJS 规范保持了很大的兼容性。 3.1 语法风格// CMDdefine(function(require, exports, module) {    var a = require('./a');    a.doSomething();    //...    var b = require('./b');   // 依赖可以就近书写    b.doSomething();    // ...     require.async('./c',function(c){ //支持异步加载        c.doSomething();    });})// AMD 默认推荐的是define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好    a.doSomething();    //...    b.doSomething();    //...})3.2 AMD和CMD的区别1) 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible(尽可能的懒加载,也称为延迟加载,即在需要的时候才加载)。2) CMD 推崇依赖就近,AMD 推崇依赖前置。虽然 AMD 也支持 CMD 的写法,同时还支持将 require 作为依赖项传递,但 RequireJS 的作者默认是最喜欢依赖前置的写法,也是官方文档里默认的模块定义写法。3.3 推荐链接与 RequireJS 的异同二、ModuleES中Module的特点浏览器,服务器通用静态加载1. 基本语法1.1 export一个模块就是一个独立的文件。export关键字用来输出模块内部的某个变量 。可以输出变量,函数或类。// test.jsexport var name = 'zhangsan';export var age = 18;// test.jsvar name = 'zhangsan';var age = 18;export { name, age };可以使用as为输出变量重命名。var name = 'zhangsan';var age = 18;export { name as personName,     age};需要特别注意的是,export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。// 报错export 1;// 报错var m = 1;export m;export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。//m.jsexport var foo = 'bar';setTimeout(() => foo = 'baz', 1000);//main.jsimport { foo } from './m1.js';console.log(1, foo);setTimeout(function () {    console.log(2, foo);}, 1000);<!DOCTYPE html><html>    <script type="module" src='./main.js'></script>    <body></body></html>//console1 "bar"2 "baz"export命令可以出现在模块的任何位置,只要处于模块顶层就可以。1.2 import其他 JS 文件通过import命令加载模块。大括号里面的变量名,必须与被导入模块(test.js)对外接口的名称相同。// main.jsimport { name, age } from './test.js';function showName() {  console.log(name);}//zhangsanimport命令输入的变量都是只读的,因为它的本质是输入接口。import {a} from './xxx.js'a = {}; // Assignment to constant variable.如果a是一个对象,改写a的属性是允许的。和const一样。import {a} from './xxx.js'a.foo = 'hello'; // 合法操作可以用星号(*)指定一个对象,进行整体加载。// main.jsimport * as test from './test.js';function showName() {  console.log(test.name);}//zhangsantest.name = 'yun';//Cannot assign to read only property 'name' of object '[object Module]'//但如果是对象,可以修改对象的属性。import命令具有提升效果,会提升到整个模块的头部,首先执行。foo();import { foo } from 'my_module';由于import是静态执行,所以不能使用表达式和变量。// 报错import { 'f' + 'oo' } from 'my_module';import语句会执行所加载的模块,因此可以有下面的写法。仅仅执行lodash模块,但是不输入任何值。import 'lodash';即使加载多次,也只会执行一次。也就是说,import语句是 Singleton 模式。1.3 单例模式解读//counter.jsexport let counter = 1;export function addCounter(){    counter++;}console.log('counter init');//main.jsimport {counter, addCounter} from './counter';console.log('main:' + counter);addCounter();console.log('main:' + counter);//counter init//main:1//main:2//从这例子中可以看出和CommonJS的区别另一个例子//main2.jsimport {counter, addCounter} from './counter';console.log('main2:' + counter);addCounter();console.log('main2:' + counter);<!DOCTYPE html><html> <head> <title>module test</title> <script type="module" src='main.js'></script> <script type="module" src='main2.js'></script> </head></html>//consolecounter initmain:1main:2main2:2main2:3从上面这个例子中可以看出,即使加载多次,也只会执行一次。并且是 Singleton 模式。1.4 export default使用export default可以不用关注输出模块中的变量名。// export-default.jsexport default function () {  console.log('foo');}// import-default.jsimport customName from './export-default';customName(); // 'foo'import命令可以为该匿名函数指定任意名字。import命令后面,不使用大括号。// export-default.jsfunction foo() {  console.log('foo');}export default foo;export default的本质,就是输出一个叫做default的变量或方法。imort something from ...的本质,就是import {default as something} from ...// 正确export var a = 1;// 正确var a = 1;export default a;// 错误export default var a = 1;// 正确export default 42;// 报错export 42;所以export default是比较常用的方法:// MyClass.jsexport default class { ... }// main.jsimport MyClass from 'MyClass';let o = new MyClass();1.5 import&export混合使用export { foo, bar } from 'my_module';// 可以简单理解为import { foo, bar } from 'my_module';export { foo, bar };上面代码中,export和import语句可以结合在一起,写成一行。但需要注意的是,写成一行以后,foo和bar实际上并没有被导入当前模块,只是相当于对外转发了这两个接口,导致当前模块不能直接使用foo和bar。// 接口改名export { fooName as newName } from 'my_module';//具名接口改为默认接口export { foo as default } from './someModule';//接口也可以改名为具名接口export { default as ES } from './someModule';1.6 模块的继承//calculator.jsexport function add(a, b) {  return a + b;}//calculatorPlus.jsexport * from './calculator.js';export function multiply(a, b) {  return a * b;}//main.jsimport * as cal from './calculatorPlus.js';cal.add(2, 3);//5cal.multiply(2, 3);//61.7 import()ES2020 (ES11)新增了 动态import特性,解决了import动态加载,和不能写在代码块中的问题。import()返回一个 Promise 对象 。import(a + '.js').then(...);      import(f()).then(...);if (condition) {  import('moduleA').then(...);} else {  import('moduleB').then(...);}2. Module补充2.1 ES模块和CommonJS模块的差异import和export是关键字,require不是。CommonJS 模块输出的是一个值的拷贝,ES 模块输出的是值的引用。(详情见上方【单例模式解读】)CommonJS 模块是运行时加载,ES 模块是编译时输出接口。    因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。this指向不同。ES 模块之中,顶层的this指向undefined;CommonJS 模块的顶层this指向当前模块,这是两者的一个重大差异。2.2 循环加载CommonJS中的循环加载// a.jslet bar = require('./b').bar;console.log('bar:', bar);exports.ada = 'ada';// b.jslet ada = require('./a').ada;exports.bar = 'bar';setTimeout(function () {    console.log('ada:', ada);}, 0);执行结果:-->node abar: barada: undefinedES Module中的循环加载// a.jsimport {bar} from './b.js';console.log('a.js', bar);export let ada = 'ada';// b.jsimport {ada} from './a.js';//console.log(ada); //此处访问ada会报错setTimeout(function () {    console.log('b.js', ada);}, 0);export let bar = 'bar';<!DOCTYPE html><html><head>    <title>module test</title>    <script type="module" src='a.js'></script></head></html>执行结果://consolea.js barb.js ada解读:因为CommonJS 模块输出的是一个值的拷贝,当拷贝的动作发生时,ada值为undefined,之后模块a中对ada进行赋值已经不会影响到模块b中保存的ada。ES 模块输出的是值的引用。所以模块a对ada进行赋值,会影响b中打印的结果。
  • [技术干货] Nest.js初探:这很Angular
    一、前言Nest是构建高效,可扩展的 Node.js Web 应用程序的框架。 它使用现代的 JavaScript 或 TypeScript(保留与纯 JavaScript 的兼容性),并结合 OOP(面向对象编程),FP(函数式编程)和FRP(函数响应式编程)的元素。 在底层,Nest 使用了 Express,但也提供了与其他各种库的兼容,例如Fastify,可以方便地使用各种可用的第三方插件。以上是Nest.js的官方介绍,其实我们只需知道,它是一款Node.js的后端框架,并且官方提到了这么一段话:Nest aims to provide an application architecture out of the box which allows for effortless creation of highly testable, scalable, loosely coupled and easily maintainable applications. The architecture is heavily inspired by Angular.翻译过来就是:Nest 旨在提供一个开箱即用的应用程序体系结构,允许轻松创建高度可测试,可扩展,松散耦合且易于维护的应用程序。并且设计灵感来自于Angular。所以这应和了这篇文章的标题,而Angular很多模式又来自于Spring框架,比如依赖注入等等,所以可以认为:Nest.js是Node.js版的Spring框架。Nest.js的社区非常活跃,Github上已经有32.9k Star。不过我们国内也有类似的Node.js框架,比如阿里出品的Midway,两者设计思路也非常类似。二、创建新应用通过Nest CLI脚手架生成一个新应用:初始化完成后,执行npm run start即可启动项目。在项目的src目录下,我们可以看到以下几个文件:main.ts是入口文件,可以看到总共就8行代码:简单来说就是使用NestFactory这个工厂函数生成一个实例,然后监听3000端口即可。这时候打开浏览器访问localhost:3000,可以看到打印出了“Hello World!”三、实现接口接下来我们来实现一个查询用户的接口,来熟悉一下基本的开发流程。第一步,创建一个module:通过脚手架命令,可以自动帮我们生成一个module文件:这时候会发现,AppModule中自动引入了该module:第二步,创建Controller:Controller就类似前端的路由,负责处理服务器响应和客户端请求。举个例子,我们要创建一个接口获取所有的用户信息,接口路径为http://localhost:3000/user/users,那么我们可以在UserController中创建一个GET方法,路径为users:当我们访问上面的接口时,就会返回“all users”。再写一个获取单个用户信息的接口: 当然,这只是Controller能力的冰山一角,官方还提供了更多的装饰器:除此之外,Nest.js里还有很多概念都与Angular一一对应,如Provider、Pipe、Guard、Interceptors等等,对于熟悉Angular的开发者来说,Nest.js可谓是量身打造的后端框架。
  • [技术干货] 什么是数据库“存算分离”架构?
        今天的话题要从一个朋友的咨询开始    所以准备写一篇短文谈谈我对“存算分离”架构的理解,不一定全面,欢迎在评论区探讨。    其实这个朋友是误解了“存算分离”这个概念。他认为普通MySQL云数据库用evs做存储,计算资源和存储资源是分开的,比如可以单独扩容计算资源或单独扩容存储资源,所以就是存算分离的架构,其实这么理解是片面的。要理解“存算分离”架构,还得追根溯源,从传统MySQL主备架构说起。    这张图熟悉MySQL的人应该都见过,我们知道,MySQL的master端有数据变更时,备机是通过读取和回放binlog,涉及到三个线程,一个运行在主节点(log dump thread),其余两个(I/O thread, SQL thread)运行在备节点,三个线程配合完成数据复制的工作。但是,不难发现,这个架构在某些场景会有明显的缺陷:主库写入压力大时。当主库的写入压力比较大的时候,主备复制的时延会变大,因为需要回放完所有binlog的事务才会完全达到数据同步。增加只读节点时。增加备机/只读节点的速度很慢,因为我们需要将数据全量的复制到从节点,如果主节点此时存量的数据已经很多,那么扩展一个备机节点速度就会很慢高。使用多个只读节点时。存储的成本线性增长,如果数据库磁盘空间比较大,那么相应的所有只读节点挂载的磁盘空间都需要和主节点一样大,成本将会随着只读库数量增加进行线性增加。    这些问题通过存算分离架构就能得到很好的解决,以华为云GaussDB(for MySQL)为例,作为华为自研的最新一代高性能企业级分布式数据库,基于华为最新一代DFV分布式存储,采用计算存储分离架构,最高支持128TB的海量存储,可实现超百万级QPS吞吐。    首先,GaussDB(for MySQL)采用计算与存储解耦的技术架构,让所有的节点都共享一个存储,也就是说,增加计算节点时,无需调整存储资源,真正做到计算与存储分离,并且可支持 15 个只读节点的扩展,主节点和只读节点之间是 Active-Active 的 Failover 方式,计算节点资源得到充分利用,由于使用共享存储,降低了用户使用成本。完美契合了企业级数据库系统对高可用性、性能和扩展性、云服务托管的需求。GaussDB(for MySQL)将MySQL存储层变为独立的存储节点,在GaussDB(for MySQL)中认为日志即数据,将日志彻底从MySQL计算节点中抽离出来,都由存储节点进行保存,与传统 RDS for MySQL 相比,不再需要刷 page,所有更新操作都记录日志,不再需要 double write,从而大大减少了网络通信。    小结一下,以“存算分离”架构来答复一下上面的3个问题:    1. 当主库的写入压力比较大的时候,由于不再有double write入,主节点和只读节点之间的复制时延基本得以消除。    2. 增加只读节点的速度非常快,因为不再需要将数据全量的复制到只读节点,无论多大数据量,只需 5 分钟左右即可完成增加只读节点。    3. 使用多个只读节点时,因为只有一份存储,所以存储的成本不会有变化,存储空间越大,只读节点越多,节省成本越明显。
  • [技术干货] MySQL+NodejS+ES的全文搜索实战
    一、Elasticsearch单独使用1、Elasticsearch安装(建议Linux系统):步骤一:安装较新版本的Java,确保环境变量配置正确,JDK版本不能低于1.7_55。步骤二:安装Elasticsearch:https://www.elastic.co/cn/downloads/elasticsearch    Linux版本$ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.10.0-linux-x86_64.tar.gz$ tar -xzf elasticsearch-7.10.0-linux-x86_64.tar.gz    windows版本:官网下载windows版本安装包,解压。2、Elasticsearch启动$ cd elasticsearch-7.10.0/$ ./bin/elasticsearch (Linux版本)$ .\bin\elasticsearch.bat (windows版本)运行成功后,浏览器访问http://localhost:9200/?pretty页面出现如下信息意味着启动成功了!!!或者打开另一个终端 执行:curl 'http://localhost:9200/?pretty' ,与上一种方式启动成功信息显示一致。(windows可以安装cURL)。可以搭配图形用户界面一起使用,安装kibana(https://www.elastic.co/guide/en/kibana/4.6/index.html), 与 elasticsearch 版本对应即可。二、Node连接MySQL1、安装ES模块$ npm install elasticsearch --save2、安装MySQL驱动$ npm install mysql --save3、这里的框架使用的是koa,先写配置文件,代码如下:4、插入数据,测试数据使用 [Faker-zh-cn.js](https://github.com/layerssss/Faker-zh-cn.js) 生成。5、使用ES全文高亮搜索,代码如下:
  • [技术干货] 初识Webpack
    1. 摘要Webpack是一种前端资源构建工具,一个静态模块打包器。在Webpack看来,前端的所有资源文件(js/json/css/img/less/…)都会作为模块处理,当Webpack处理应用程序时,它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源。Webpack打包流程图如图1-1所示。图1-1 Webpack打包流程图2. Webpack五个核心概念2.1 Entry入口(Entry)指示Webpack以哪个文件作为入口起点分析构建内部依赖图并进行打包。2.2 Output输出(Output)指示Webpack打包后的资源bundles输出到哪里去,以及如何命名。2.3 LoaderLoader让Webpack能够去处理那些非JavaScript语言的文件,Webpack本身只能理解JavaScript。2.4 Plugins插件(Plugins)可以用于执行范围更广的任务,插件的范围包括从打包和压缩,一直到重新定义环境中的变量等。2.5 Mode模式(Mode)指示Webpack使用相应模式的配置。分为development和production两种模式,下面分别进行简述。development: 开发模式,能让代码本地运行的环境,会将process.env.NODE_ENV的值设为development,同时启用NamedChunksPlugin和NamedModulesPlugin插件;production: 生产模式,能让代码优化运行的环境,会将process.env.NODE_ENV的值设为production,同时启用FlagDependencyUsagePlugin、FlagIncludedChunksPlugin、ModuleConcatenationPlugin、NoEmitOnErrorsPlugin、OccurrenceOrderPlugin、SideEffectsFlagPlugin和UglifyJsPlugin插件。3. Wbepack配置3.1 webpack.config.js文件webpack.config.js是webpack的配置文件,用来指示webpack工作,运行webpack指令时,会加载里面的配置,所有构建工具都是基于nodejs平台运行的,默认采用commonjs模块化。webpack.config.js基础配置如图3-1所示。图3-1 webpack.config.js基础配置3.2 devServer配置开发服务器(devServer)用来实现自动化(自动编译、自动打开浏览器、自动刷新浏览器),只会在内存中编译打包,不会有任何文件输出,本地安装webpack-dev-server后,通过npx webpack-dev-server命令启动devServer,核心代码如图3-2所示。图3-2 devServer配置核心代码3.3 打包html/样式/图片/其它资源打包不同的资源会使用不同的loader和插件,打包html/样式/图片/其它资源的流程如下所述。3.3.1 打包html资源1.下载html-webpack-plugin插件;2.引入html-webpack-plugin插件;3.使用html-webpack-plugin插件,并进行相应配置。3.3.2 打包样式资源不同的样式文件需要配置不同的loader1.下载loader;2.配置loader,css样式文件使用css-loader和style-loader,less文件使用less-loader、css-loader和style-loader。其中css-loader的作用是将css文件变成commonjs模块加载到js文件中,style-loader的作用是创建style标签,将js中的样式资源插入进去,添加到head中生效。3.3.3 打包图片资源1.下载url-loader,file-loader2.配置loader3.3.4 打包其它资源1.下载file-loader2. 配置loader,配置该loader作用于不为html/css/less/js的其他文件3.4 提取css成单独文件/css兼容性处理/压缩css3.4.1  提取css成单独文件样式文件打包后会默认和js文件一起输出,可以通过插件将打包后的css文件单独输出,流程如下所述。1.下载mini-css-extract-plugin插件2.引用该插件3.配置3.4.2 css兼容性处理1.下载postcss-loader和postcss-preset-env2.在package.json中browsetslist属性中分别对开发环境和生产环境进行兼容性配置,设置支持样式的浏览器版本3.通过postcss找到package.json中browserslist里面的配置,通过配置加载指定的css兼容性样式。3.4.3 压缩css1.下载optimize-css-assets-webpack-plugin插件2.引用该插件3.使用该插件3.5 js语法检查eslint/js兼容性处理/js压缩3.5.1 js语法检查eslint1.下载eslint-loader和eslint2.在package.json中的eslintConfig中进行配置3.配置eslint-loader,其中只需检测js文件并要排除第三方库,只检测自己写的源代码,同时可在options配置中设置fix:true,自动修复eslint的错误。3.5.2 js兼容性处理    1.下载babel-loader、@babel/core、@babel/preset-env,通过@babel/preset-env做基本的js兼容性处理,然后通过corejs做前面无法实现的兼容性处理,并实现按需加载    2. 配置loaderjs兼容性处理核心代码如图3-3所示图3-3 js兼容性处理核心代码3.5.3 js压缩mode设置为production生产环境时会自动压缩js代码。4. webpack性能优化可以从开发环境和生产环境分别对webpack进行性能优化。其中开发环境主要考虑从打包构建速度和代码调试两个方面进行优化,生产环境主要考虑从打包构建速度和代码运行性能这两个方面进行优化。下面简单介绍下开发环境上通过HMR提升构建速度。4.1 HMR    HMR(热模块替换),作用是一个模块发生变化后,只会更新打包这一个模块而不是所有模块,通过在devServer中设置hot:true属性启动HMR功能。其中对于样式文件,可以使用HMR功能,因为style-loader内部实现了;对于js文件,默认不能使用HMR功能,解决方法:修改入口文件js代码,添加支持HMR功能的代码,另外HMR只能处理非入口js文件的其他文件,对入口文件并不能生效,因为一旦入口文件更新,入口文件引入的其他文件一定会被重新加载;对于html文件,默认不能使用HMR功能,同时会导致html文件不能热更新,解决方法:修改entry入口文件,将html文件引入,只能解决html文件不能热更新的问题。js文件支持HMR功能的核心代码如图4-1所示。图4-1 js文件支持HMR功能核心代码4.2  HMR效果在入口index.js文件中引入print.js文件,运行npx webpack-devserver后,页面如图4-2所示。4-2 初始页面修改print.js文件后,只会重新加载print.js文件,而不会重新加载index.js文件,HMR效果如图4-3所示。4-3 HMR效果图
  • [技术干货] 编码规范轻体验
    前言编码规范指的是针对特定编程语言约定的一系列规则,通常包括文件内容组织、缩进、注释、声明、语句、空格、命名约定、编程实践、编程原则和最佳实践等。 比如各类方法的命名约定:查询的方法以get或query做前缀;插入的方法以add或insert做前缀;删除的方法以delete或remove做前缀;……如果你对编码规范已经有了一定了解,那么我们继续往下。规范制定编码规范制定一般会参考业界公认的标准,在通用的编码规范基础上,再结合公司、项目的要求而形成的。编码规范制定的目标是为了实现团队成员代码一致性和最佳实践,通过代码风格的一致性,降低维护代码的成本以及改善多人协作的效率。同时遵守最佳实践,确保页面性能得到最佳优化和高效的代码。校验工具目前前端领域主要的代码静态检查工具有JSLint 、JSHint、 JSCS和ESLint等。它们各有的优缺点,本文不再详述,如有兴趣可自行了解。如何选择校验工具依据项目实际情况而定,本人比较推荐ESLint,因为它对ES6支持的最广泛,下面内容将会以ESLint如何在项目开发中实际应用展开。ESLint简介ESLint 是在 ECMAScript/JavaScript 代码中识别和报告模式匹配的工具,它的目标是保证代码的一致性和避免错误。 安装npm install eslint --save-devESLint规则可以通过以下两种主要的方式来配置:Configuration Comments - 使用 JavaScript 注释把配置信息直接嵌入到一个代码源文件中。Configuration Files - 使用 JavaScript、JSON 或者 YAML 文件为整个目录(处理你的主目录)和它的子目录指定配置信息。可以配置一个独立的 .eslintrc.* 文件。配置说明ESLint 附带有大量的规则。你可以使用注释或配置文件修改你项目中要使用的规则。要改变一个规则设置,你必须将规则 ID 设置为下列值之一:"off" 或 0 - 关闭规则"warn" 或 1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出)"error" 或 2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)比如通过设置.eslintrc.js强制使用一致风格的反勾号、双引号或单引号。{    "rules": {        "quotes": ["error", "double"] // 要求尽可能使用双引号    }}编码规范应用实践Visual Studio Code+ESLint环境准备:Node.js、git、Visual Studio Code在VSCode扩展页搜索ESLint,下载并安装完成后应用到工作区,就可以实现IDE的智能提示。Git Hooks+ESLint Git hooks能够在发生某特定行为的时机,触发执行自定义的脚本。 我们可以通过pre-commit来触发执行git commit命名时的一些自定义脚本,比如代码静态检查。依赖huskyInclinthuskyhusky是用node实现的一个快速安装git hooks的工具。安装npm install husky --save-devpackage.json配置"husky": {    "hooks": {      "pre-commit": "npm run inclint"    } },Inclintinclint 是用来对每次改动的文件执行 eslint,提高 eslint 执行的速度。安装npm install inclint --save-dev命令及参数inclint -c path/to/eslintrc --targetDir dir[,dir2,...,dirn]options:   -c path 必须,指定 eslint 配置文件的路径--targetDir 必须,提供一个或多个需要检查的目录,注意多个目录用,分割package.json配置{  "lint": "inclint -c ./.eslintrc --targetDir ./src",}husky+Inclint一起使用时的配置如下:{  "dependencies": {    "eslint-config-angular": "^0.5.0",    "eslint-config-xo-space": "^0.21.0",    "eslint-plugin-angular": "^4.0.0",  },  "devDependencies": {    "eslint": "^5.7.0",    "eslint-config-prettier": "^3.1.0",    "eslint-loader": "^2.1.1",    "husky": "^3.0.1",    "inclint": "^1.0.6",  },  "scripts": {    "lint": "inclint -c ./.eslintrc --targetDir ./src",    "fix": "eslint --fix src",  },  "husky": {    "hooks": {      "pre-commit": "npm run lint"    }  }}提交代码git add * // 将修改的文件提交到暂存区git commit -m 'xxx' // 将暂存区里的改动给提交到本地的版本库,触发执行pre-commit中的自定义脚本npm run fix // 通过eslint自带命令修复代码门禁代码门禁指在某些特定的场景下(比如开发者提交MR到主干库、出包构建等)触发的一系列测试,使得主干代码能维持在某一个程度的质量标准,例如:编译必须通过,代码重复率、圈复杂度不能高于某个水平、静态代码扫描必须通过、开源无风险、安全检查通过等等,一般使用Jenkins完成环境搭建和门禁配置。因每个项目的要求不一,此处不再详细的讲述。如有需求可以使用云服务提供商的代码构建服务,比如华为云的代码检查 CodeCheck :https://support.huaweicloud.com/productdesc-codecheck/devcloud_pdtd_30001.html
  • [技术干货] MongoDB经典故障系列四|调整oplog大小,引起从库宕机怎么办?
总条数:21 到第
上滑加载中