关于实践:实践教程之PolarDBX-replica原理和使用

前置筹备假如曾经依据前一讲内容实现了PolarDB-X的搭建部署,能够胜利链接上PolarDB-X数据库。 PolarDB-X作为MySQL的备库本步骤将领导您如何应用PolarDB-X作为MySQL的备库。1.建设复制链路。a.切换至终端一,执行如下命令,登录云服务器ECS_1实例中的MySQL阐明:您须要将如下命令中的替换为云服务器ECS_1实例上的MySQL 8.0的初始密码。mysql -uroot -p<PASSWORD>b.执行如下命令,批改MySQL的root用户的初始密码为Aliyun123! 残缺内容请点击下方链接查看: https://developer.aliyun.com/article/1176275?utm_content=g_10... 版权申明:本文内容由阿里云实名注册用户自发奉献,版权归原作者所有,阿里云开发者社区不领有其著作权,亦不承当相应法律责任。具体规定请查看《阿里云开发者社区用户服务协定》和《阿里云开发者社区知识产权爱护指引》。如果您发现本社区中有涉嫌剽窃的内容,填写侵权投诉表单进行举报,一经查实,本社区将立即删除涉嫌侵权内容。

May 5, 2023 · 1 min · jiezi

关于实践:实践教程之用PolarDBX搭建一个高可用系统

前置筹备假如曾经依据前一讲内容实现了PolarDB-X的搭建部署,能够胜利链接上PolarDB-X数据库。 启动业务本步骤将领导您如何应用Sysbench OLTP场景模仿业务流量。 1.筹备压测数据。a.执行如下SQL语句,创立压测数据库sysbench_test。create database sysbench_test; b.输出exit退出数据库。 残缺内容请点击下方链接查看: https://developer.aliyun.com/article/1176268?utm_content=g_10... 版权申明:本文内容由阿里云实名注册用户自发奉献,版权归原作者所有,阿里云开发者社区不领有其著作权,亦不承当相应法律责任。具体规定请查看《阿里云开发者社区用户服务协定》和《阿里云开发者社区知识产权爱护指引》。如果您发现本社区中有涉嫌剽窃的内容,填写侵权投诉表单进行举报,一经查实,本社区将立即删除涉嫌侵权内容。

May 5, 2023 · 1 min · jiezi

关于实践:跟随项曙明走进中兴通讯探索企业开源风险治理优秀实践

点击收听“大咖访谈”第11期:https://m.ximalaya.com/sound/625970244?from=pc (倡议在WiFi下播放) 开源雨林:请您简短地向观众介绍本人大家好,我是项曙明,目前在中兴通讯做开源合规治理工作,是中兴通讯开源合规 & 平安治理总监、开源社正式成员、2022 中国开源先锋 33 人。开源雨林:请问您何时开始接触开源?为何对开源治理感兴趣?我从 2014 年开始接触开源,对开源治理感兴趣次要与我的工作经验无关,我自己曾负责 EPG 组长,对研发过程改良十分相熟,开源治理对我来说就是研发过程改良中新增的一部分内部束缚而已,从无序到有序,我集体有人造的偏好,也是职业的使然。 开源雨林:请问您何时及为何投身开源治理?中兴通讯很早就构建了欠缺的研发管理机制和危险管控体系,每年均要在本身从事的业务畛域寻找 TOP 危险,2014 年左右我在公司产品平台部门工作,市场一线的危险是产品线关注的焦点,平台部门的危险辨认我认为开源合规是一个长期而艰巨的危险点,它应该属于研发过程改良的一部分,将与产品研发过程及其改良长期共存,是一个很好的职涯钻研方向,构建升高开源应用危险的企业级管控机制对企业、对集体都有益处,也比拟有挑战性,所以从那时起我开始投身开源治理的学习和钻研。 开源雨林:请问您对国内企业开源治理的现状有何评估?我集体认为,国内曾经过了开源治理的布道阶段,大家已不再探讨是否须要应用开源的问题。更多的开始关注如何合规和平安地应用开源,然而在如何系统化地构建企业无效的开源合规 & 平安管控机制方面,绝大多数的企业没有这方面的意识或者不晓得该如何着手,更多的还只是停留在具体的许可证合规、某一个安全漏洞的打消等细节点上,中兴通讯很早就退出了国际化的行列,并把合规和开源合规作为整个企业的经营基石之一。 开源雨林:TODO Group 提到了使用期、参加期、奉献期、领导期这样这几个阶段,那像中兴通讯这样的先行者,您感觉贵司目前处在哪一阶段呢?我感觉中兴通讯目前在开源治理方面应该是处于整个行业的领导期阶段,咱们在组织层面通过了大略六七年的摸索与实际,遇到和克服了很多不同的业务治理场景,曾经积攒了相当多的开源治理教训和教训,同时也积极参与内部开源社区,奉献开源社区。 实际上,大多数企业第一个阶段都是应用开源,把开源软件使用于产品的研发过程中,为企业的产品开发和经营服务。企业在应用开源软件的过程中会发现,开源软件自身的合规和平安问题十分多,而且这些危险是必须要企业本人来承当的。这些开源软件绝大多数在企业里是没有专门的团队来进行守护的,也不可能将所有的开源软件都守护起来,那么在这样的场景下,企业如何高效地将这些应用到的开源软件合规和平安方面的危险升高,是否能通过外部开源的形式将这些开源我的项目以另一种研发模式进行异地/异步开发,将其守护起来?当初行业里也在探讨开源社区的我的项目是否能依照可信开源我的项目进行经营治理,以晋升其合规性和安全性、升高相应危险。企业能够依据本人的理论状况进行抉择。 开源雨林:贵司的开源治理单位是怎么组建起来的?这两头有没有什么挑战和艰难?开源治理波及软件开发、经营的所有畛域和过程,所以开源治理单位注定只能是一个虚构的组织,从公司 OSPO 办公室,到开源治理畛域的相干专家,直至笼罩到有软件开发的所有我的项目团队,有相干开源治理职责的团队成员至多有几百人。波及的角色次要有:开源 COP 团队成员、过程改良专家、法务专家、产品/平台经理、研发代表、我的项目开源治理接口人、零碎工程师、我的项目团队、开源软件守护我的项目/守护人、知识产权专家、IPR 经理、配置管理员、QA/PME、ECC、我的项目合规经理、平安团队、供应链团队、规范团队、开源奉献团队。 因为开源治理涉及面十分广,很难在一个组织内成立一个专职的部门来进行治理,所以从 2014 年开始,咱们首先是在研究院层面建设开源治理团队,到 2016 年在公司层面成了开源 COP(Community of Practices:实际社区)团队,笼罩到公司所有应用到软件的产品和团队,逐渐构建了一套笼罩 EAR(Export Administration Regulations,美国进口管理条例)合规、开源合规、产品安全和 GDPR(个别数据保护条例)在内,从市场商机到产品运维全过程的管控应答机制,以升高产品的合规 & 平安危险,晋升客户应用我司产品的满意度和信任度。次要的挑战是如何无效地协调各方独特参加到开源的治理工作中来。 开源雨林:在开源应用方面,有没有一些比拟有意思的事件或者挑战能够分享?第一个挑战:企业用了多少开源软件?用了多少许可证?这些开源软件是怎么用的?这一块儿就十分难以答复;第二个挑战:如何把存量应用的开源治理好、合规应用好?第三个挑战:开源软件看不见摸不着,如何高效和无效地进行治理以配合开源软件的合规管控须要。 在这些场景下,要有一套卓有成效的管理体系,能实在、清晰地理解企业到底用了哪些开源软件,这些软件在我的项目版本中是如何应用的。没有这些根底能力,做开源治理的成果必定会大打折扣。此外,对于 License 的治理,我所看到的是大家都还停留在比拟通俗的层面上。我认为还是要想分明以上几点,也就是解决治理中 “ 我在哪里?” 的问题,并联合组织策略明确开源治理的指标,也就是 “ 我要去哪里?”,而后通过对标,能力提出开源治理过程中的改良需要,否则真的很难提出治理指标和每年的治理需要,也就难以动手治理了。 开源雨林:供应链治理方面,对于平安、合规的治理简单吗?简单。一个产品一开始可能只需一个开发团队开发,前面随着组织规模扩充和产品多元化,就会提出平台化开发需要而变成多个项目组(产品、平台、组件)共同开发一个产品。开源软件的引进,软件开发逐渐演变为以模块化、组装化、多元化的混源开发模式。但咱们发现,公司外部团队间接开发的软件,个别会依照组织的研发治理要求,其合规性和安全性相对来说是有保障的,而引进的开源软件,因为开源软件的固有属性其合规性、安全性是不能保障的。 此外,项目组在内部引入的过程中,不仅会从开源社区引入,还会有一些商业软件、外包软件、开发软件、SDK 等第三方软件的引入,并成为产品组成的一部分。所以在引入上述第三方软件时,第三方组织是否了解开源合规,其在版本散发时的合规性和安全性是否失去保障,这个也是须要管控的。 市面上还有很多所谓的凋谢软件,咱们在社区或者是公开的中央都能下载到,这些软件的危险也十分大。如果没有对开发人员的 “开源软件” 引入过程进行管控,这些软件就很容易地被引入进来,但其往往都存在开源合规和平安的危险。 所以我认为要想把它做好,须要将引入、应用、治理和应答等方方面面的“管控破绽”建设起一套无效的管理体系,对所有开源软件和第三方软件进行全生命周期治理。而这些开源软件和第三方软件的全生命周期治理,因为不同的类别在企业里其引入时波及的畛域、部门都不雷同,相应的流程要别离去梳理和建设,过程会很简单,比拟难实现。 开源雨林:中兴通讯在开源治理方面这么多的教训,有没有思考将实践经验及理念对外界做分享呢?大家都晓得开源要做合规和平安的管控,也有很多企业会做一些优良实际的分享,我认为还是要依据本身的理论状况以及特有的流程,联合本人的实际,能力真正无效地落地。 中兴通讯近几年来,积极参与国内国内开源社区、标准化组织的各种分享、规范制订工作,特地是无关开源治理方面的教训和理念的分享曾经有很多。 开源雨林:对 TODO Group 的冀望?其实很多做软件开发的企业,我感觉他们在不同场景下遇到的问题应该和中兴通讯、华为、甚至国外头部企业遇到的问题是一样的,所以在参加国内社区,以及国外的一些 TODO Group 时,大家在理论治理过程中遇到的问题,这些问题呈现后是怎么解决或者如何将问题危险升高的,相互之间都有一些参考价值,所以冀望 TODO Group 可能踊跃收集治理过程中的问题和治理实际,多多提供合作、交换分享,互相学习的机会。 ...

April 13, 2023 · 1 min · jiezi

关于实践:得物复杂-C-端项目的重构实践

1. 背景1.1 重构Q:什么是重构? 重构是在不扭转软件可察看行为的前提下,改善其内部结构。--《重构 - 改善既有代码的设计》   Q:为什么要重构? 重构能够进步了解性和升高批改老本 。--《重构 - 改善既有代码的设计》   Q:什么时候重构?   (1)何时不应该重构? 没有价值,没有意义或者投入产出比很低时。团队资源是无限的,无限的资源应该尽可能投入到有意义的事件下来。从团队的角度思考投入产出比,对于曾经只是保护状态,如无需要、无调整的代码,不要去动它,如果对于老手而言,不仅不会带来益处反而可能挖坑,要晓得既有代码可能有不少坑。   (2)何时应该重构? 我的项目保护老本很高影响我的项目调优,如性能优化时代码长得丑,不优雅时既有设计和实现不利于扩大新性能时重复性工作,既有的代码无奈帮忙你轻松增加新个性时修补 bug 时,排查逻辑艰难code review 能够让别人来复审代码查看是否具备可读性,可了解性太多的代码无正文,未然连本人都无奈疾速理清代码逻辑  1.2 如何重构(1)筹备(基本功) 举荐值得一读再读经典书籍,重构圣经《重构 - 改善既有代码的设计》 。自己从毕业第一年开始,几年下来读了 4 遍 +,受益匪浅,每次温习都能有所播种,让我常常折腾经手的我的项目却没出过问题。   (2)重构实际要点 思考分明(整体有设计,不肯定要文档化但须要想分明)。协同布局(开发团队外部的配合及重构分支与其余分支的集成、内部资源提前申请如产品、测试、运维等)、整体规划。分层分步开展,抓大放小从粗到细。善用 “批处理”。一次只做一件事。不要反复造轮子。当你感觉一件事很难的时候,停下来思考是不是办法用错了,它应该是怎么的。放弃监控及复盘本人的思考形式。做好对内和对外沟通,尤其在当我的项目不是只有一个人在开发和保护的状况下。留神提前和相干方(测试、运维)沟通好(计划、次要工夫节点、须要投入的资源、须要其配合的事项)。  2. 社区 C 端的重构实际  本次重构具备肯定的复杂度,除了技术迁徙革新的老本外,波及的几个仓库是不同技术选型(框架 & 下层组件等)、我的项目疾速的麻利迭代、需要高并发及多人协同开发保护状态。   2.1 现状剖析  技术栈:  仓库名技术栈社区 C 端页面数repo AReact + umi3指标仓库无需统计repo BReact + umi35repo Cvue2 + vuex27  我的项目侧  三个仓库 A / B / C 更新沉闷,每个仓库均波及多业务线的开发,并行保护。别离依照 2 周一个 sprint 的迭代节奏开展,1 周开发 1 周测试,间或穿插着 hotfix。 ...

June 22, 2022 · 4 min · jiezi

关于实践:咸阳市大数据管理局使用Rainbond作为智慧城市底座的实践

应用 Rainbond 作为智慧城市底座之后,给咱们带来了成倍的运维效率晋升。 —— 咸阳市大数据管理局 熊礼智咸阳市大数据管理局负责全市信息共享工作的组织领导,协调解决与政府信息共享无关的重大问题,钻研拟订并组织施行全市大数据策略、布局和政策措施,疏导和推动大数据钻研和利用工作,建设全市对立的数据服务中心和信息共享机制。通过“端-边-网-云-智” 的全新技术架构,实现治理高效、服务便民、产业倒退、生态谐和的指标效用,达成新一代信息技术与城市现代化深度交融,迭代演进的新模式、新理念。 智慧城市的建设中,对智慧城市利用的治理是个很根底的问题。传统的状况下,服务于民生的各类利用零碎,都是由相应的政府部门各自部署管辖,这造成了一些困扰。各个城市部门往往各自为政,彼此之间造成数据孤岛,很难互通互联。无论是数据还是利用,都很难对立治理起来。 在咸阳智慧城市建设工作中重点建设数据交换共享平台和利用治理平台。数据交换共享平台负责买通城市各个部门的数据孤岛,进行数据清理和规约之后,最初达成所有城市部门的 IT 利用之间互联互通的成果。 在建设咸阳市智慧城市期间,咱们在智慧城市利用治理畛域遭逢了很多辣手的问题。为了解决这些痛点,咱们借助 Rainbond 这款产品,建设起了能够提供自动化运维能力的利用治理平台。我从四个局部分享解决难题的整个过程: 痛点:回顾智慧城市利用,在部署施行以及前期运维上的难点痛点。 定位:咱们如何定位智慧城市利用治理平台,以及心愿通过它解决什么样的问题。 落地:简要论述智慧城市利用治理平台的选型过程,以及部署落地的过程。 实战:讲一个实在的案例,来阐明引入利用治理平台后,疾速开发落地一个智慧城市利用的全过程。 传统模式下的痛点我将痛点归纳如下: 不足对立治理:以往各个城市部门的利用零碎的部署是横七竖八的。每家单位都在建设本人的 IT 零碎,没有对立的治理可言。遗留零碎多:很多城市部门的利用零碎应用的工夫都很久了,有的零碎甚至曾经失去了厂家的反对。而有的零碎采纳的技术曾经过期,无奈不便的迁徙到能够被集中管理的环境中去,也没有方法很好的将它们监控起来,取得其实时的状态。资源分配不合理:每家单位都在进行 IT 零碎的建设,这必然导致做了很多重复性的建设工作,资源节约随之而来。而且在不足资源监控的状况下,没有谁能说分明各自的利用零碎到底应该应用多少资源。访问量不管多少,都调配了同样的资源,不足合理性。运维艰难:每家单位建设 IT 零碎的形式办法形形色色。而这些单位本身往往不足相应的技术人才来保护这些零碎,一旦出了问题,每套业务零碎的保护形式都不一样。不足可观测性:以往的 IT 零碎建设,往往仅仅关注应用程序自身,而疏忽了可观测性的建设。无奈做到问题疾速发现,往往 IT 零碎的失灵,是由用户反馈而来的。对利用治理平台的定位利用治理平台负责承载和治理所有智慧城市上司的利用零碎,包含新建设起来的数据交换共享平台。后续所有新开发的智慧城市利用会间接基于利用治理平台部署,以往老旧的遗留零碎也会随着迭代更新一直迁徙到利用治理平台。这么做的目标就是为了可能逐渐整合各个城市部门的数据与利用,对立治理。 建设智慧城市的过程中,必然会不断涌现出少量新的城市部门利用零碎,如何在建设过程中不重走老路很重要。智慧城市利用治理平台在这个过程中表演的角色是GPaaS 平台,数据交换共享平台是VPaaS 的一部分。二者相结合,能够将海量城市数据在云端实现会集融通计算,在进步城市智慧体运行速度的同时也大大降低了运行老本。我将利用治理平台和数据交换共享平台的定位总结如下: 利用治理平台向下对立纳管所有计算资源。实现计算资源统一分配调度。这些计算资源以多个机房内托管的虚拟机或者物理机的模式提供。利用治理平台应提供资源监控面板,并在底层计算资源呈现问题时发送报警信息。利用治理平台向上承载包含数据交换共享平台在内的所有智慧城市利用零碎。提供对立格调的治理面板,以及丰盛的自动化运维能力,最大水平升高利用运维治理的难度。智慧城市利用能够以极低的代价迁徙到利用治理平台上来,可能实时统计利用的拜访流量和资源占用状况,实现计算资源面向利用按需分配,主动调整。利用治理平台横向延长到各个城市部门。数据交换共享平台须要借助利用治理平台的这一能力,与城市部门现有 IT 零碎接驳。利用治理平台能够接收老旧遗留零碎。对于无奈间接迁徙到利用治理平台的各类老旧遗留零碎,比方 Windows 利用等,应能够至多做到逻辑层面的接入,可能以对立格调的面板进行简略治理,以及衰弱检测等监控能力。 落地过程与价值体现咱们选型并比照了多款 PaaS 平台类产品,最终抉择了 Rainbond 。回顾过后的选型过程,以及零碎建成到当初的应用体验,我将其劣势总结如下: 易用性好:Rainbond 是多家选型产品中,易用性做的最好的一款产品。一站式的产品化体验让咱们在智慧城市利用的开发部署,乃至前期的运行保护工作中都大大降低了学习老本。数据交换共享平台这个外围利用,仅用不到一周的工夫,就实现了向云端的迁徙。弱小的自动化运维能力:在运维治理方面,其自动化运维能力十分优良,节俭了大量运维老本,使运维效率成倍晋升。可观测性:Rainbond 提供了全面的监控报警零碎,无论是计算资源还是下层的利用零碎,一旦呈现问题都能够很快裸露进去。联合自动化运维能力,问题利用零碎能够做到自愈自复原。而通过观察利用零碎访问量和资源耗费状况,能够更正当的进行资源分配工作。开源生态:Rainbond 自身是个开源产品,也拥抱开源社区生态。其外部的利用商店零碎,提供了大量咱们须要的第三方中间件,这些中间件能够一键部署到利用治理平台下来,这节约了大量的工夫和精力。否则基于服务器从零搭建这些中间件零碎十分耗时耗力。基于 Rainbond 建设的利用治理平台于 2019年11月落地交付使用。这套利用治理平台底层对接了3个不同的集群,别离是开发测试环境、一般生产环境和涉密生产环境。时至今日,其上部署的各类城市利用曾经超过了 100 套,组件数量超过500个。 最先被迁徙到利用治理平台上的数据交换共享平台。向开发测试环境迁徙的过程比拟轻松,咱们投入了两名开发人员、两名运维人员,在好雨科技交付工程师的配合下,基于源代码就将所有的组件部署到了利用治理平台上。所有的学习和迁徙工作只继续了一周左右就实现了。接下来要思考的,是在生产环境中部署这套利用零碎。咱们在这里借助了 Rainbond 外部组件库提供的能力,将开发测试环境中的数据交换共享平台,公布到了外部组件库中,在生产环境中就能够一键部署了。后续的降级操作也都借由利用模版配套的版本治理性能实现,这极大的节约了部署降级老本。 数据交换共享平台须要借助平台能力,延长到各个城市部门接驳其已有的 IT 零碎。最开始 Rainbond 并不反对这个非凡的需要,最终定制了特制的网关,使数据交换共享平台能够通过网关和城市部门已有的 IT 零碎交互。 数据交换共享平台部署状态: 在利用的运维治理方面,最让咱们感觉好用的,是 Rainbond 提供的对立网关配置性能。通过非常简单的配置,就能够将平台上部署的利用零碎对外裸露服务地址。而且通过了定制,咱们应用的 Rainbond 网关反对了国密证书,使得咱们在安可方面的要求也失去了满足。 ...

November 19, 2021 · 1 min · jiezi

关于实践:得物技术时间切片的实践与应用

0x1:前言每一个领有【高级资深】title的前端工程师,必定会对我的项目的整体性能优化有本人的独到见解。这是往前端业务架构方向转变的必须要具备的能力之一。 本文就给大家介绍一个性能优化的伎俩之一:工夫切片(Time Slicing) 依据W3C性能小组的介绍,超过50ms的工作就是长工作。 序号工夫散布形容10 to 16 msUsers are exceptionally good at tracking motion, and they dislike it when animations aren't smooth. They perceive animations as smooth so long as 60 new frames are rendered every second. That's 16 ms per frame, including the time it takes for the browser to paint the new frame to the screen, leaving an app about 10 ms to produce a frame.20 to 100 msRespond to user actions within this time window and users feel like the result is immediate. Any longer, and the connection between action and reaction is broken.3100 to 1000 msWithin this window, things feel part of a natural and continuous progression of tasks. For most users on the web, loading pages or changing views represents a task.41000 ms or moreBeyond 1000 milliseconds (1 second), users lose focus on the task they are performing.510000 ms or moreBeyond 10000 milliseconds (10 seconds), users are frustrated and are likely to abandon tasks. They may or may not come back later.表格内容摘抄自应用 RAIL 模型评估性能 ...

October 22, 2021 · 3 min · jiezi

关于ui:得物技术分布式-UI-自动化实践

前言提起 UI 自动化测试,总是会有人抛出很多疑难: UI 自动化能带来什么价值吗?还是在浪费时间?UI 自动化测试在整个测试流程中表演什么样的角色?有编写 UI 自动化测试的工夫,我早就实现业务测试了,我为什么还要编写自动化测试的 case 呢?针对于 UI 界面常常变动的业务场景,编写和保护自动化 Case 几乎太难了,怎么样能力解决这些问题呢?...... 明天小编就在这里跟大家分享下,本人对 UI 自动化测试的了解以及我司品质平台正在搭建的分布式平台 DuLab 是怎么实现批量运行 UI 自动化测试 Case 的。 为什么要做 UI 自动化?随着不停的版本迭代,软件新增性能变的越来越多,对测试资源的需要也变得越来越大,执行人工测试的工夫越来越长。对于人工测试的依赖开始变得辣手,因而大家开始寻找解决方案,UI 自动化也应运而生。 人工测试的弊病人工回归测试须要破费很长时间能力实现,很小的提早就会让公布面临危险。公布节奏受到人工回归测试的限度。两天以上的人工回归测试意味着最好的状况下可能一个月公布两次。而且,开发者须要一次性公布所有货色。要么全副公布,要么什么都公布不了,因为须要将所有货色一起测试。UI 自动化测试的长处解放了测试团队针对长期的和探索性案例的测试工夫;能够一边开发一边进行回归测试,缩小等待时间;可重复性应用,疾速进行回归测试;更好的利用资源(周未/早晨的资源闲暇时段)。UI 自动化的特点UI 即 User Interface(用户界面)的简称,UI 自动化做的事件就是模仿用户行为进行操作,实现对用户界面的测试。这也就从实质上限度了它的应用场景: 软件需要变动不频繁产品更新保护周期长比拟频繁的回归测试自动化测试脚本可重复使用所以在你开始之前,最好意识分明哪些业务场景是能够自动化的~ 预期成果针对我司的业务现状,确定好预期成果。 兼容性测试:针对市场上罕用机型与零碎版本,进行下载安装应用,以发现兼容性故障,进而修复。埋点测试:校验埋点数据是否失常上报,有无漏报,错报,多报。回归测试:版本迭代中,进行回归测试保障代码改变不会导致其余场景产生故障。测试阶段性能收集:在测试阶段为自动化 case 指定优先级,依照优先级运行自动化 case,提供更多的性能数据。思路与接口自动化测试思路雷同,咱们在进行 UI 自动化测试时,每个 Case 都是一个独自的 TestCase,咱们将所有须要执行的 case 放在同一个 TestSuit 中,批量执行并生成聚合报告。 难点不同于接口自动化,单个客户端设施某个时刻仅反对运行一个自动化 Case;受制于电脑性能,无奈在繁多电脑设备上同时管制数十台挪动设施;随着版本迭代,局部 Case 仅实用于某些 APP 版本,需限度版本范畴;无奈省略前置步骤,比方说想要对某个页面进行 UI 自动化,无奈间接进入该页面,要从启动 APP 开始,抉择前置门路能力进入指定页面;雷同场景下数据可能会发生变化,使得校验规定无奈对立;不同账号下,数据不同,可能会导致很多场景无奈测试;对各种零碎各种型号的挪动设施,进行近程管制;如何在 UI 自动化的过程中校验埋点数据;大量的 AB 试验,如何切换环境进行测试;APP 安装包的治理,如何抉择安装包进行笼罩装置.......架构上面是小编本人从点到面一步步的思考历程,从根本的挪动设施远程管理,case 编写到 case 的保护,再到 lab 平台的搭建: ...

April 23, 2021 · 2 min · jiezi

关于前端:得物技术前端性能监控实践

前言对于前端来说,最重要是的体验,而在前端体验中,最为外围的就是性能。秒开率、晦涩水平等一系列指标都间接影响用户体验。 因而,建设一个精确、及时、无效的前端性能监控零碎,不仅能够量化以后页面的性能程度,还能够为优化计划的成果提供数据反对,此外,还能够在页面性能下滑时提供报警服务,揭示开发人员改善页面性能。 监控指标的选取在参考前人的实际成绩后,咱们对性能监控的一系列指标的计算成本,适用性和实用价值进行了评估,认为以下指标和信息是最具实用性和性价比的: 首先是 fcp(first contentful paint,如下图所示),这个指标是目前统计页面秒思考的支流指标,尽管它不如 fmp(First Meaningful Paint、lcp(Largest Contentful Paint)、speedIndex 等指标更贴近用户实在应用体验,然而长处是在 Android 端通过调用 Performance API 即可取得,在 iOS 能够通过 raf(requestAnimationFrame)估算,施行过程简略。 其次是 tts(time to server),这个指标并没有呈现在此前看到的文章里边。 它形容的是用户连贯到服务器的工夫,通过 Performance API 中提供的 requestStart 减去 fetchStart 失去,这个指标不是前端能够通过技术能够优化的,然而它能够反映在以后用户群体的网络环境下,页面秒开率的下限是多少。 举个例子,如果通过性能监控数据发现,有 15%的用户拜访,须要破费至多 1s 的工夫能力连贯到咱们的服务器(能够是 SSR 服务器,也能够是 CDN),那么这些用户无论如何都不能秒开,那么此时,某页面秒开率的下限就是 85%。 如果当前情况下,这个页面的秒开率曾经达到了 75%甚至更高,那么持续优化的边际收益会非常低,应该适可而止了。 第三是 tsp(time for server processing),这个指标也没有呈现在此前的参考文章里。 它针对的是在应用 SSR 的场景下,服务器外部解决页面申请的耗时,可通过 Performance API 中提供的 responseStart 减去 requestStart 失去。 这个环节性能太差,亦会成为连累秒开率的一个瓶颈,所以必须予以监控;tsp 太长会压迫其余环节的性能估算,太小会增大服务器运维老本。 第四是 css 文件、图片等资源的大小、xhr 申请的持续时间,前两种资源如果不加节制,会导致页面即使做到秒开,也无奈疾速进入可用状态,比方常见的 feed 流页面。 对于 xhr,须要进行分类探讨,如果是 SSR 页面,则影响不大,只有保障 tsp 处于较低水平,基本上不会连累秒开率,但如果是 SPA,页面次要功能区都依赖后端数据反对的,比方判断权限、展现 feed 流内容,xhr 的响应速度就十分要害了,也须要予以监控,在指标下滑时,告诉后端予以优化和解决。 ...

April 16, 2021 · 1 min · jiezi

关于工具软件:SSH连接服务器后执行多条命令

[TOC] SSH连贯服务器后执行多条命令大家平时有没有遇到本人连贯云服务器,ssh 连贯下来之后,发现自己的一些小工具用不了 例如go build无奈应用 ,因为咱们装置配置golang 环境的时候,是在文件/etc/profile中写了配置,因而须要source 一下/etc/profile 那么是否能够在ssh 连贯上服务器的时候就能够立刻主动执行这一类命令呢? 咱们的智慧无穷无尽,小工具也是十分的多,明天来讲述一下SSH连贯服务器后执行多条命令能够如何做 1 应用分号隔开应用 分号 ;来隔开命令 附带1条命令 ssh User@Host 'source /etc/profile'附带多条命令 ssh User@Host 'source /etc/profile ; uptime'2 应用管道符号隔开应用管道|来隔开命令 附带1条命令 ssh User@Host 'source /etc/profile'附带多条命令 ssh User@Host 'source /etc/profile | uptime'3 应用写EOF的形式同样实用于一条 / 多条命令 ssh User@Host << EOF> ls -al> source /etc/profile> EOF4 应用脚本的形式应用脚本的形式花色就更多了,例如有一个脚本myinit.sh在/home/admin/code/ 上面 myinit.sh #!/bin/bashsource /etc/profilels -al近程连贯服务器 ssh User@Host 'bash -s' < /home/admin/code/myinit.sh以上四种形式,按需索取,很可 以上为本期全部内容,如有疑难能够在评论区或后盾提出你的疑难,咱们一起交换,一起成长。 好家伙要是文章对你还有点作用的话,请帮忙点个关注,分享到你的朋友圈,分享技术,分享高兴 技术是凋谢的,咱们的心态,更应是凋谢的。拥抱变动,背阴而生,致力向前行。 作者:小魔童哪吒

April 4, 2021 · 1 min · jiezi

关于golang:golang环境安装

[TOC] golang装置下载golang软件【国内网站】https://studygolang.com/dl go语言中文网下载 go最新的安装包,依据不同的零碎,能够抉择 windows,linux,mac【能够上外网的话】拜访go语言英文网站 https://docs.studygolang.com/...解压langtar -C /usr/local -xzf go1.16.linux-amd64.tar.gz配置golang将go的二进制目录增加到PATH环境变量 vim /etc/profileexport GOROOT=/usr/local/goexport PATH=$PATH:$GOROOT/bin从新导入配置source /etc/profilegolang配置正确下载资源go env -w GO111MODULE=on go env -w GOPROXY=https://goproxy.cn,direct若呈现报错: warning: go env -w GOPROXY=... does not override conflicting OS environment variable则间接批改此处,将 https://goproxy.cn,direct 填入如下地位 以上为本期全部内容,如有疑难能够在评论区或后盾提出你的疑难,咱们一起交换,一起成长。 好家伙要是文章对你还有点作用的话,请帮忙点个关注,分享到你的朋友圈,分享技术,分享高兴 技术是凋谢的,咱们的心态,更应是凋谢的。拥抱变动,背阴而生,致力向前行。 作者:小魔童哪吒

April 3, 2021 · 1 min · jiezi

关于golang:JWT身份认证附带源码讲解

[TOC] JWT(Json Web Token)验证(附带源码解说)一天,正是午休时段 兵长路过胖sir座位,大吃一惊,明天胖sir竟然没有打呼噜,而是在低着头目不转睛盯着一本书 兵长凑近一看,胖sir竟然在看史书... 兵长:(轻声道),你在看 什 么 ~~ 胖sir:我在想我要是穿梭到清朝,我会是啥身份? what??~~~ , 能是啥身份,必定是重量级人物呗 胖sir: 我呸, 明天我倒要给你讲讲啥叫身份 讲到身份,不得不说一下cookie、session、Token的区别,come on 1 cookie、session、Token的区别CookieCookie总是保留在客户端中,按在客户端中的存储地位,可分为 内存Cookie 和 硬盘Cookie。 内存Cookie由浏览器保护,保留在内存中,浏览器敞开后就隐没了,其存在工夫是短暂的。 硬盘Cookie保留在硬盘⾥,有⼀个过期工夫,除⾮⽤户⼿⼯清理或到了过期工夫,硬盘Cookie不会被删除,其存在工夫 是⻓期的。 所以,按存在工夫,可分为 ⾮长久Cookie和长久Cookie。 那么cookies到底是什么呢? cookie 是⼀个⾮常具体的东⻄,指的就是浏览器⾥⾯能永恒存储的⼀种数据,仅仅是浏览器实现的⼀种数 据存储性能。 cookie由服务器⽣成,发送给浏览器 ,浏览器把cookie以key-value模式保留到某个⽬录下的⽂本⽂件 内,下⼀次申请同⼀⽹站时会把该cookie发送给服务器。因为cookie是存在客户端上的,所以浏览器加⼊ 了⼀些限度确保cookie不会被歹意使⽤,同时不会占据太多磁盘空间,所以每个域的cookie数量是无限的。 SessionSession字⾯意思是会话,次要⽤来标识⾃⼰的身份。 ⽐如在⽆状态的api服务在屡次申请数据库时,如何 晓得是同⼀个⽤户,这个就能够通过session的机制,服务器要晓得以后发申请给⾃⼰的是谁,为了辨别客户端申请, 服务端会给具体的客户端⽣成身份标识session ,而后客户端每次向服务器发申请 的时候,都带上这个“身份标识”,服务器就晓得这个申请来⾃于谁了。 ⾄于客户端如何保留该标识,能够有很多⽅式,对于浏览器⽽⾔,⼀般都是使⽤ cookie 的⽅式 ,服务器使⽤session把⽤户信息长期保留了服务器上,⽤户来到⽹站就会销毁,这种凭证存储⽅式绝对于 ,cookie来说更加平安。 然而session会有⼀个缺点: 如果web服务器做了负载平衡,那么下⼀个操作申请到 了另⼀台服务器的时候session会失落。 因而,通常企业⾥会使⽤ redis,memcached 缓存中间件来实现session的共享,此时web服务器就是⼀ 个齐全⽆状态的存在,所有的⽤户凭证能够通过共享session的⽅式存取,以后session的过期和销毁机制 须要⽤户做管制。 Tokentoken的意思是“令牌”,是⽤户身份的验证⽅式,最简略的token组成: uid(⽤户唯⼀标识) + time(以后 工夫戳) + sign(签名,由token的前⼏位+盐以哈希算法压缩成⼀定⻓度的⼗六进制字符串) ,同时还可 以将不变的参数也放进token 这里说的token只的是 JWT(Json Web Token) ...

March 31, 2021 · 5 min · jiezi

关于golang:一看便会微信后台服务器开发

微信后盾服务器开发就要上班了,兵长关上手机,看到弹出的某微信聊天机器人广告便点了进去,于是有了如下故事... 最近兵长在看微信的时候突发奇想的去玩了一下某微信机器人,可能像智能语音助手一下和本人聊天 兵长就在想,这机器人是咋做的,咱们是做服务器开发的,咱用go语言疾速实现一下给本人玩玩,实现一个定制化的聊天机器人可好 胖sir听到兵长喃喃自语的不明所以,便走上前说,咋开始玩起聊天了,不来峡谷游了吗? 上次带你原本是想带你成为winer的,没想到,每一把都是loser,我打算最近收收手,管制一下情绪,找机器人安慰一下我手上的心灵 你是说微信聊天机器人吗?哪些不都是千篇一律的嘛 那么你能弄个定制化的嘛?把我情绪弄好了,我带你来大乱斗吧 ~~(偷笑),小伙子,还好我留了一手,我先给你说说微信后盾服务器如何初步开发一个简略的你问我答性能吧,授人以渔,不如授人以鱼是不 开发一个微信后盾服务器作为被动回复机器人,大抵分为如下几步: 开明公众号,注册微信公众号开发平台,这里能够是注册订阅号,具体的前面给你说配置权限,配置微信后盾开发者权限流程介绍接入微信后盾性能实现兵长乱斗带胖sir飞开明公众号注册微信公众号开发平台,这里能够是注册订阅号,依照提醒进行注册输出信息即可,置信你一看就会 注册地址:https://mp.weixin.qq.com/cgi-bin/registermidpage?action=index&lang=zh_CN&token= 我整顿了一个表格来介绍一下订阅号和服务器号的区别,你也能够先初步理解一下区别,前面能够缓缓推敲 订阅号服务号用处次要目标 为大家流传征询;相似报纸,杂志,集体输入偏差企业或组织的交互,如银行,商场,餐厅等;自助服务的服务号,用于企业群发次数一天能够发送一次;所有的订阅号推送音讯,会被对立收纳到订阅号栏目中一个月发送4条群发音讯展现地位全副收录在 订阅号的 信息栏中展现在好友音讯列表之中;关注一个服务号,即相当与加了一个敌人微信领取不可开明领取性能认证后 能够开明微信领取性能自定义菜单绝对简略绝对高级,微信有接口,能够自行开发配置权限配置微信后盾开发者权限 进入公众号治理页面,下拉右边侧,进入根本配置 URL:填写本人的外网服务器URL,如果没有能够买一个云服务器,当初买云服务器还是很便宜的Token:自定义Token,用于制作签名,这个十分重要,须要窃密EncodingAESKey:随机生成即可音讯加解密形式:为了演示不便,咱们这里应用明文模式微信公众号后盾接口权限普通用户只有是接管音讯和主动回复音讯的权限 流程介绍开发被动回复音讯流程介绍,简略来说,能够是这样的 性能实现必备知识点http服务进行通信Token机制微信后盾开发xml的数据序列化http服务做上述被动回复音讯的性能,此处仅须要后盾服务器实现get办法和post办法即可 get办法 次要是用于,咱们在微信后盾设置token的时候,微信后盾会向咱们的服务器发送get申请,判断咱们服务是否有正确的数据 post办法次要是用于,粉丝在咱们的微信后盾发送音讯的时候,是以post的形式发送给咱们的后盾服务器的 Token机制参数形容signature微信加密签名,signature联合了开发者填写的token参数和申请中的timestamp参数、nonce参数。timestamp工夫戳nonce随机数echostr随机字符串开发者通过测验signature对申请进行校验(上面有校验形式)。若确认此次GET申请来自微信服务器,请原样返回echostr参数内容,则接入失效,成为开发者胜利,否则接入失败。加密/校验流程如下: 1)将token、timestamp、nonce三个参数进行字典序排序 2)将三个参数字符串拼接成一个字符串进行sha1加密 3)开发者取得加密后的字符串可与signature比照,标识该申请来源于微信 token算法流程图 验证办法(get) 1.服务器端获取token、nonce、timestamp组成列表2.列表排成字典序3.排序后的元素进行摘要4.摘要比对signature5.响应echostr参考微信后盾开发文档连贯:https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Getting_Started_Guide.html xml数据解析兵长,不晓得你有没有用过xml来做数据的序列化,此处你必定会问,为什么用xml,而不必json,不必protobuf 来我给你简略介绍一下xml: XML是可扩大标记语言,其中标记指的是计算机中所能了解的信息符号,通过标记计算机之间能够解决蕴含各种信息的资源,咱们能够通过通用的标记语言来进行标记 用人话来说就是,xml是数据序列化的其中一种形式,微信定下来应用该形式来对数据进行序列化,咱们须要对此进行开发,因而也须要遵循微信的规定 例如 微信后盾的 text音讯类型 申请 xml格局如下 文本音讯,微信公众平台申请微信后盾服务器会带的字段有:FromUserName,ToUserName,CreateTime,MsgType,Content,MsgId 咱们开发的微信后盾服务器,须要依照如下数据格式做回复:xml 带上如下字段ToUserName,FromUserName,CreateTime,MsgType,Content 兵长,再给你回顾一下,实现微信后盾服务器被动回复音讯的服务,须要用到上述说到的3点,http服务、token机制、xml解析,记住咯,我要开始撸代码了 具体实现main.go 启动http服务器,开始监听80端口package mainimport ( "fmt" "github.com/wonderivan/logger" "net/http" "time")const ( port = 80 //后盾服务器端口号80,本人的公网服务器 须要设置防火墙,关上80端口 token = "XXXXXXX")// 须要本人批改token,以适应本人公众号的tokenfunc main() { logger.SetLogger("./log.json") logger.Info(" ------------ start main ------------") server := http.Server{ Addr: fmt.Sprintf(":%d", port), // 设置监听地址, ip:port Handler: &httpHandler{}, // 具体应用哪个handler来解决 ReadTimeout: 5 * time.Second, // 读写超时 微信给进去 5秒 WriteTimeout: 5 * time.Second, MaxHeaderBytes: 0, } logger.Info(fmt.Sprintf("Listen: %d", port)) logger.Fatal(server.ListenAndServe())}route.go ...

March 17, 2021 · 2 min · jiezi

关于实践:无侵入式mock平台在得物的实践

一、概述1.1 背景介绍作为测试应该都遇到过如下两大痛点: 1.只想测试被测系统A,却须要从依赖零碎开始一层层造本人想要的测试数据,造数破费工夫长,边界值及异样场景不好模仿。 2.接口自动化,UI自动化,埋点自动化因为服务或者测试数据的不稳定性导致自动化保护老本高。 要解决上述问题,根本都会想到mock。目前市面上有很多优良的开源mock框架:Mockito、PowerMock、EasyMock、JMockit等,但这些框架对于咱们当初的业务场景及次要是在集成测试过程中应用,显然不是咱们想要的。因为咱们心愿在不改变开发代码的状况下反对得心应手的结构mock接口的返回报文来测试不同的业务场景,基于这种内部依赖服务走http模式的技术架构,一套无侵入式的mock平台应运而生。 hulk是一个无侵入式的http mock平台,反对客户端代理,从网关层mock,反对后端服务之间的mock。反对返回报文函数配置,并且具备放行逻辑。将来还将反对filter,依据不同的入参返回不同的mock数据。 1.2 零碎架构基于Django + mitmproxy + vue + MongoDB + MySQL 目前整个技术架构比较简单,mock服务基于Django框架开发,代理层次要是在开源框架mitmproxy根底上做了二次开发买通和mock零碎的交互,前端配置平台应用了公司的脚手架poizon-cli。数据存储次要用了MongoDB和MySQL,进步性能后续会思考引入redis,将配置信息缓存到redis中升高接口响应工夫。 1.2.1 服务端mock时序图 1.2.2 客户端mock时序图 二、mock服务2.1 部署及性能通过Nginx + Uwsgi + Django部署,反对高并发 能够间接通过测试组jenkins构建部署 部署脚本: # 服务器我的项目地址# shellcheck disable=SC2164cd /home/dhk/workspace/hulkpython37 -m venv venv # 生成虚拟环境source venv/bin/activate # 启动虚拟环境python37 -m pip install --upgrade pip # 降级pippython37 -m pip install -r requirements.txt # 装置依赖库# shellcheck disable=SC2164cd /home/dhk/workspace/hulk/hulk #进到uwsgi.ini目录# shellcheck disable=SC2006# shellcheck disable=SC2009# 获取uwsgi父过程pid=`ps -ef | grep "uwsgi" | grep -v grep | awk '{print $2}' | awk 'NR==1{print}'`if [ -n "$pid" ]then uwsgi --reload uwsgi.pidelse uwsgi --ini uwsgi.inifi性能:在4C8G的机器上的单机性能指标 ...

January 29, 2021 · 3 min · jiezi

关于实践:亲历者说-完整记录一年多考拉海购的云原生之路

作者 | 张洪箫(花名:伏见)阿里巴巴新批发高级技术专家起源|阿里巴巴云原生公众号 前言考拉海购的整个云化革新是从 2019 年 10 月份开始的,过后的惟一指标就是短时间内疾速实现迁徙。在不到 4 个月的工夫里,考拉团队惟一思考的是如何以最快的速度完成使命,云原生是咱们抉择的最合适的一条路。 实际历程 本篇次要从第三阶段的云产品接入和第四阶段运研模式的降级来谈谈考拉海购的实际过程。 云产品接入1. 云原生产品定义云原生实质上是一套技术体系和方法论。随着容器技术、可继续交付、编排零碎等技术的倒退,同时在开源社区、散布式微服务等理念的带动下,利用上云曾经是不可逆转的趋势。真正的云化不仅仅是基础设施和平台的变动,利用自身也须要做出扭转。在架构设计、开发方式、利用运维等各个阶段基于云的特点,面向开源和标准化,建设全新的云化的利用,即云原生利用。 云原生技术有利于各组织在私有云、公有云和混合云等新型动静环境中,构建和运行可弹性扩大的利用。依据 CNCF 的定义,云原生的代表技术包含容器、服务网格、微服务、不可变基础设施和申明式 API。阿里云提供了音讯队列产品,如音讯队列 RocketMQ 版、音讯队列 Kafka 版等,利用实时监控服务 ARMS,微服务引擎 MSE,利用高可用服务 AHAS,性能测试 PTS,函数计算 FC 等中间件云原生产品,为考拉海购从传统利用向云原生利用演进,打下了松软的根底。 2. 心路历程咱们在云产品的接入过程中, 大抵在心态上经验了三个阶段。 1)第一阶段:很好、很弱小,接入效率杠杠的这部分次要是在 2019 年 10 月 - 2020 年 3 月之前,那时候接入的都是数据库、Redis,以及 ASI 这种产品,绝对用户比拟多,整体比较稳定,与开源产品基本上齐全兼容,迁徙工具及周边建设都比较完善,所以迁徙起来十分安稳,基本上改变一部分点就能够了。 2)第二阶段:云产品真丰盛,要啥都有以前很多组件还是咱们本人保护的,然而随着连贯实例的减少,读写的次数多了,时不时呈现宕机。那时候据说微服务引擎 MSE 很好用,它提供一站式微服务能力加持,包含微服务依赖组件托管、无侵入的微服务治理,更快捷、稳固、低成本的运行微服务。咱们找了下 MSE 的兄弟,他们拍着胸口说没问题,产品运行之后真的就没呈现过那些问题了。 像这样的例子还很多,那时候的感触是,只有真正体系化地去应用云原生产品,你才会对云原生的价值有更粗浅的感触。 3)第三阶段:磨合适应随着考拉海购开始接入团体的业务平台,供应链也开始和团体进行交融,咱们也进一步发展云化的历程。过程中也有挑战,不过在克服重重困难后,咱们如期完成了各项的革新,并且十分安稳的度过了几次大促,云原生产品十分好地撑持了考拉海购业务的增长。 3. 接入的过程1)接入策略因为云产品和考拉海购自建的产品有肯定的能力差异,所以咱们建设了一整套产品评估和接入试验田机制来保障整个接入的有序及性能的可迁移性,正是这套机制的良好运行,咱们整个的稳定性失去了保障,在整个根底大变动中都没有呈现大的故障。 咱们的整个保障流程如下图: 2)权限计划接入云产品面临的第一个问题是,云账号,云产品资源权限怎么治理?阿里云自身提供了 RAM 产品,作为治理用户身份与资源拜访权限的服务。那么 RAM 账号如何何员工身份关联? 是为每个产品申请一个子账号,所用人共用该子账号?还是为每个人申请一个 RAM 子账号,独自为每个人治理资源权限?或者为利用申请一个子账号,通过员工的利用权限来和子账号的资源权限做关联?考拉海购有几百人,计划2和3都面临着很高的子账号生命周期以及资源权限的治理老本,所以咱们初期在应用这些中间件云产品时,出于简略思考,都采纳了第一个计划——申请一个子账号,开发一起用。 其带来的问题就是资源权限粒度太粗,比方应用任务调度(SchedulerX) ,  登录到控制台就能够操作所有利用的所有工作,这对于平安生产来说,自身就是一件很危险的事件。所以为了利用平安,咱们向中间件云产品提的第一个需要,基于 RAM 提供按利用粒度做资源受权的能力。 考拉海购用户在登录云控制台时,感知不到 RAM 账号。在基于 RAM 云产品  STS(Security Token Service) 的能力,封装了一层简略的云控制台跳转长期受权,在生成 STS Token 时,依据 BUC 获取以后用户,并生成和指定一个额定的权限策略,限度该用户操作云资源(利用)的权限。登录页面如下图: ...

January 21, 2021 · 2 min · jiezi

诗和远方蚂蚁金服-Service-Mesh-深度实践-QCon-实录

2019 年,蚂蚁金服在 Service Mesh 领域继续高歌猛进,进入大规模落地的深水区。本文整理自蚂蚁金服高级技术专家敖小剑在 QCon 全球软件开发大会(上海站)2019 上的演讲,他介绍了 Service Mesh 在蚂蚁金服的落地情况和即将来临的双十一大考,以及大规模落地时遇到的困难和解决方案,助你了解 Service Mesh 的未来发展方向和前景。前言大家好,我是敖小剑,来自蚂蚁金服中间件团队,今天带来的主题是“诗和远方:蚂蚁金服 Service Mesh 深度实践”。 在过去两年,我先后在 QCon 做过两次 Service Mesh 的演讲: 2017年,当时 Service Mesh 在国内还属于蛮荒时代,我当时做了一个名为“Service Mesh: 下一代微服务”的演讲,开始在国内布道 Service Mesh 技术;2018年,做了名为“长路漫漫踏歌而行:蚂蚁金服 Service Mesh 实践探索”的演讲,介绍蚂蚁金服在 Service Mesh 领域的探索性的实践,当时蚂蚁金服刚开始在 Service Mesh 探索。今天,有幸第三次来到 QCon,给大家带来的依然是蚂蚁金服在 Service Mesh 领域的实践分享。和去年不同的是,今年蚂蚁金服进入了 Service Mesh 落地的深水区,规模巨大,而且即将迎来双十一大促考验。 备注:现场做了一个调研,了解听众对 Servicve Mesh 的了解程度,结果不太理想:在此之前对 Service Mesh 有了解的同学目测只有10%多点(肯定不到20%)。Service Mesh 的技术布道,依然任重道远。今天给大家带来的内容主要有三块: 蚂蚁金服落地情况介绍:包括大家最关心的双十一落地情况;大规模落地的困难和挑战:分享一下我们过去一年中在大规模落地上遇到的问题;是否采用 Service Mesh 的建议:这个问题经常被人问起,所以借这个机会给出一些中肯的建议供大家参考;蚂蚁金服落地情况介绍发展历程和落地规模 Service Mesh 技术在蚂蚁金服的落地,先后经历过如下几个阶段: 技术预研 阶段:2017年底开始调研并探索 Service Mesh 技术,并确定为未来发展方向;技术探索 阶段:2018年初开始用 Golang 开发 Sidecar SOFAMosn,年中开源基于 Istio 的 SOFAMesh;小规模落地 阶段:2018年开始内部落地,第一批场景是替代 Java 语言之外的其他语言的客户端 SDK,之后开始内部小范围试点;规模落地 阶段:2019年上半年,作为蚂蚁金融级云原生架构升级的主要内容之一,逐渐铺开到蚂蚁金服内部的业务应用,并平稳支撑了618大促;全面大规模落地 阶段:2019年下半年,在蚂蚁金服内部的业务中全面铺开,落地规模非常庞大,而且准备迎接双十一大促;目前 ServiceMesh 正在蚂蚁金服内部大面积铺开,我这里给出的数据是前段时间(大概9月中)在云栖大会上公布的数据:应用数百个,容器数量(pod 数)超过10万。当然目前落地的pod数量已经远超过10万,这已经是目前全球最大的 Service Mesh 集群,但这仅仅是一个开始,这个集群的规模后续会继续扩大,明年蚂蚁金服会有更多的应用迁移到 Service Mesh。 ...

November 5, 2019 · 5 min · jiezi

Keras快速风格迁移的实践

本文是对Github项目misgod/fast-neural-style-keras的实践。 实践过程下载并解压该GitHub项目。在images文件夹中新建output文件夹和train文件夹。在train文件夹文件夹中放入你的数据集。在images文件夹中style文件夹放入你的风格图片。导入包:这是我反复测试得到的,pip install scipy==1.2.1和pip install keras==2.1.2,使用这些版本会减少很多报错。训练模型:python train.py --style 风格图片名。注意:风格图片名不要带.jpg文件后缀。应用模型:自行参考该项目:python transform.py -i image/content/101.jpg -s la_muse -b 0.1 -o out。各种报错的解决方法报错:ImportError: cannot import name '_obtain_input_shape'参考:https://www.cnblogs.com/sssal...解决:vgg16.py第18行处,使用keras_applications代替keras.applications。 报错:ImportError: cannot import name 'imsave'参考:https://blog.csdn.net/weixin_...解决:pip install scipy==1.2.1 报错:ModuleNotFoundError: No module named 'sklearn'解决:pip install sklearn 报错:AttributeError: module 'keras.backend' has no attribute 'image_dim_ordering'参考:https://blog.csdn.net/w568841...解决:vgg16.py中第87行将include_top改为require_flatten。 报错:FileNotFoundError: [WinError 3] 系统找不到指定的路径。:'images/train/'解决:在images文件夹中新建train文件夹。 报错:FileNotFoundError: [Errno 2] No such file or directory: 'images/output/风格图片名_0.png'解决:在images文件夹中新建output文件夹。 报错:Found 0 images belonging to 0 classes.……ZeroDivisionError: integer division or modulo by zero参考:https://cloud.tencent.com/dev...解决:图片不能直接放在train文件夹中。需在train文件夹中再新建一个文件夹,再将图片放入新建文件夹中。 ...

October 14, 2019 · 1 min · jiezi

快速风格迁移在Colab上的实践

〇、快速风格迁移风格迁移是CV的一个应用,通过融合风格图片和内容图片,实现图片的风格变换,“人人都是艺术家” 最早在论文《A Neural Algorithm of Artistic Style》中提出,但是这种方法是用“训练”的思想来做风格迁移,每次都要单独训练,速度很慢 快速风格迁移由《Perceptual Losses for Real-Time Style Transfer Super-Resolution》提出,主要是将风格迁移的训练和应用分离,可以快速应用引用自:https://blog.csdn.net/jianbin...本文是对Github项目 fast-neural-style-tensorflow 在Google Colab上的实践。 一、在计算机上实践前期准备clone该GitHub项目并解压。在该目录新建pretrained文件夹、generated文件夹、models文件夹和train2014文件夹。如需体验直接应用模型的过程,可以在 百度网盘 下载原作者已训练好的七个模型到models文件夹中。下载VGG16模型并解压到pretrained文件夹中。下载COCO数据集到train2014文件夹中。使用pip安装tensorflow等所需包,这里我不再列出。(我的环境是Python3.6,请不要使用Python3.7,我在另一篇文章中提到了原因)实践过程将你的风格图片放在img文件夹中。下面我以lu.jpg这张图片为例。配置yml文件:复制conf文件夹中的任一yml文件并重命名为风格图片名.yml(例如我重命名为lu.yml)将第2行、第3行的绿框处改为你的风格图片名。将第8行的红框处改为你的风格权重。(风格权重的数值需要自行测试得出最佳。)以上你就配置好了yml文件,可以开始训练了。开始训练:在该项目所在目录打开命令行,使用python train.py -c conf/风格图片名.yml进行训练。(如果你同时安装了Python3.6、Python3.7两个版本,可参考我在另一篇文章中的办法,将python.exe重命名。我训练时使用的命令是python36 train.py -c conf/lu.yml.)经过漫长漫长的等待(我用了足足两天,经历了12120个step),在你models/风格图片名目录下出现了fast-style-model.ckpt-done文件,这就是训练好的模型了。(如果你等不及你也可以在整千个step的时候使用以下命令,将done替换为你当前的step即可。)应用模型:在该项目所在目录打开命令行,使用python eval.py --model_file 模型路径 --image_file 内容图片路径即可应用该模型(如我:python36 eval.py --model_file ./models/lu/fast-style-model.ckpt-done --image_file img/test.jpg)。该过程只需十秒左右。在generated文件夹中将生成res.jpg,就是你本次应用输出的图片了。二、在Colab上的实践由于在自己的计算机上训练真是太漫长太漫长太漫长了,所以我推荐在Google Colab上运行,训练时间大概只需6个小时。 前期准备可参考我的文章:Google Colab的使用方法 实践过程1.将所需文件(fast-neural-style-tensorflow-master文件夹)存于Google硬盘中。2.使用以下代码装载Google硬盘: from google.colab import drivedrive.mount('/content/drive')3.使用以下代码更改运行目录: import osos.chdir("/content/drive/fast-neural-style-tensorflow-master") //替换为你文件夹存放的目录4.使用以下代码训练模型,该过程需约六个小时: ! python train.py -c conf/lu.yml //替换为你配置的yml文件5.使用以下代码应用模型,该过程仅需几秒: ! python eval.py --model_file ./models/lu/fast-style-model.ckpt-done --image_file img/test.jpg //与计算机中运行命令一致6.在generated文件夹中将生成res.jpg,就是你本次应用输出的图片了。

October 7, 2019 · 1 min · jiezi

风格迁移在Colab上的实践

〇、风格迁移什么是图像风格迁移?图像风格迁移即是输入一张代表内容的图片和一张代表风格的图片,深度学习网络会输出一张融合了这个风格和内容的新作品。引用自:https://blog.csdn.net/qq_3061...本文是对GitHub项目 Neural-Style 在Google Colab上的实践。此外,我也进行了 快速风格迁移在Colab上的实践 ,欢迎大家阅读! 一、前期准备可参考我的另一篇文章:Google Colab的使用方法 。 下载该GitHub项目并解压。下载imagenet-vgg-verydeep-19.mat到该目录下。(请自行寻找并下载VGG19)将整个Neural-Style-master文件夹上传到Colab硬盘。二、实践过程1.新建Colab笔记本,代码执行程序->更改运行时类型请修改为Python2和GPU。(请务必使用Python2!使用Python3将提示AttributeError: module 'scipy.misc' has no attribute 'imread') 2.使用以下代码装载Google硬盘: from google.colab import drivedrive.mount('/content/drive')3.使用以下代码更改运行目录: import osos.chdir("/content/drive/My Drive/Colab Notebooks/Neural-Style-master") //替换为你文件夹存放的目录4.使用以下代码生成图片,该过程需约200秒: ! python neural_style.py --content 内容图片路径 --styles 风格图片路径 --output 生成图片路径如原文中: ! python neural_style.py --content examples/cat.jpg --styles examples/2-style1.jpg --output y-output.jpg

October 7, 2019 · 1 min · jiezi

Mongodb的实践二初识

Mongodb 系列教程Mongodb的实践一:安装Mongodb的实践二:初识Mongodb的实践三:Mongodb的实践四:Mongodb的实践五:Mongodb的实践六:Mongodb的实践七:Mongodb的实践八:术语db->数据库collection->集合document->文档index->索引cluster->集群shard->分片 数据类型MongoDB文档存储是使用BSON类型类型的官方文档:https://docs.mongodb.com/manu...BSON官网:http://bsonspec.org/ TypeNumberAliasNotesDouble1“double” String2“string” Object3“object” Array4“array” Binary data5“binData”Undefined6“undefined”Deprecated.ObjectId7“objectId” Boolean8“bool” Date9“date” Null10“null” Regular Expression11“regex” DBPointer12“dbPointer”Deprecated.JavaScript13“javascript” Symbol14“symbol”Deprecated.JavaScript (with scope)15“javascriptWithScope” 32-bit integer16“int” Timestamp17“timestamp” 64-bit integer18“long” Decimal12819“decimal”New in version 3.4.Min key-1“minKey” Max key127“maxKey” 常用数据类型后续实例说明 内建的角色组https://docs.mongodb.com/manu... Database User Roles 这个是针对非系统数据库和部分系统表的角色组Database Administration Roles 可以操作所有数据库Cluster Administration Roles 管理员族 针对整个系统进行管理Backup and Restoration Roles 备份还原角色组All-Database Roles 角色里面有一些跟超管差不多了级别了,针对所有数据库的Superuser Roles 超级管理员 不用多说了Internal Role 内部系统角色MongoDB 通过角色基本权限控制授予(用户)数据和命令的使用权,并且提供给内置角色数据系统一般需要的不同层次的权限。另外,你也可以创建用户定义角色。 角色授予对定义的资源执行一组操作的权限。给定的角色应用于定义它的数据库,并且可以授予对粒度集合级别的访问权限 MongoDB的每个内置角色在数据库级别为角色数据库中的所有非系统集合定义访问权限,在收集级别为所有系统集合定义访问权限MongoDB在每个数据库上提供内置的数据库用户和数据库管理角色。MongoDB仅在管理数据库上提供所有其他内置角色。 本节描述每个内置角色的权限。您还可以随时查看内置角色的权限,方法是发出rolesinfo命令,并将showprivileges和showbuiltinroles字段都设置为true。 Database User Roles (数据库用户角色)每个数据库都包含以下客户角色: read(只读)提供读取所有非系统集合和以下系统集合上的数据的能力:system.indexes, system.js, and system.namespaces集合 ...

July 8, 2019 · 4 min · jiezi

Mongodb的实践一初始包括安装

Mongodb 系列教程Mongodb的实践一:初始(包括安装)Mongodb的实践二:Mongodb的实践三Mongodb的实践四Mongodb的实践五Mongodb的实践六Mongodb的实践七Mongodb的实践八序言Mongodb 教程其实早在一年前就一直想写一写,因为工作比较忙,自己也没有真的大量用于真实项目里的实践,一直耽搁了 简介MongoDB是一个基于分布式文件存储的数据库. 官网https://www.mongodb.com/downl... 单机安装三种安装支持 1. window安装可参考mongodb单机 在window下安装测试 2. 类unix系下安装wget https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-4.0.6.tgztar zxvf mongodb-osx-ssl-x86_64-4.0.6.tgzcd mongodb-osx-ssl-x86_64-4.0.6/binmongod --config /xx/xx.config --fork3. docker安装# -p local_port:docker_portdocker pull mongo:4.1.5docker run -d --name mongodb-4.1.5 -e MONGO_INITDB_ROOT_USERNAME=root -e MONGO_INITDB_ROOT_PASSWORD=123456 -v /data/mongodb/docker/4.1.5:/mongodb -v /data/mongodb/docker/4.1.5/conf.d:/etc/mongo -p 27077:27017 mongo:4.1.5 --config /etc/mongo/mongod.conf --authdocker 目录结构├── conf.d│   └── mongod.conf├── data└── logsmongod.conf/data/mongodb/docker/4.1.5/conf.d下的mongo配置文件 # mongod.conf# for documentation of all options, see:# http://docs.mongodb.org/manual/reference/configuration-options/# Where and how to store data.storage: dbPath: /mongodb/data journal: enabled: true# engine:# mmapv1:# wiredTiger:# where to write logging data.systemLog: destination: file logAppend: true path: /mongodb/logs/mongod.log# network interfacesnet: port: 27017# bindIp: 127.0.0.1# bindIp: 0.0.0.0# how the process runsprocessManagement: timeZoneInfo: /usr/share/zoneinfosecurity: authorization: enabled#operationProfiling:#replication:#sharding:## Enterprise-Only Options:#auditLog:#snmp:连接测试mongo --host 127.0.0.1 --port 27077> db.auth("root", "123456")1> show dbs;admin 0.000GBconfig 0.000GBlocal 0.000GB创建新数据和账号> use demo;switched to db demo> db.createUser({... user : "demo",... pwd: "123456",... roles : [... {... "role" : "dbAdmin",... "db" : "demo"... },... {... "role" : "dbOwner",... "db" : "demo"... }... ],... "mechanisms" : [... "SCRAM-SHA-1",... "SCRAM-SHA-256"... ]... });Successfully added user: { "user" : "demo", "roles" : [ { "role" : "dbAdmin", "db" : "demo" }, { "role" : "dbOwner", "db" : "demo" } ], "mechanisms" : [ "SCRAM-SHA-1", "SCRAM-SHA-256" ]}> exit;测试插入和查询# 需要重连mongo --host 127.0.0.1 --port 27077>db.auth("demo","123456");1> dbdemo> db.foo.insert({"name":"qkl",age:"18",sex:1});WriteResult({ "nInserted" : 1 })> show dbs;demo 0.000GB> show collections;foo> db.foo.find({}){ "_id" : ObjectId("5d22db4bbcbb35d902a31a92"), "name" : "qkl", "age" : "18", "sex" : 1 }> db.foo.insert({"name":"hax",age:"16",sex:0});WriteResult({ "nInserted" : 1 })> db.foo.find({}){ "_id" : ObjectId("5d22db4bbcbb35d902a31a92"), "name" : "qkl", "age" : "18", "sex" : 1 }{ "_id" : ObjectId("5d22dbafbcbb35d902a31a93"), "name" : "hax", "age" : "16", "sex" : 0 }

July 8, 2019 · 2 min · jiezi

深度-API-设计最佳实践的思考

阿里妹导读:API 是模块或者子系统之间交互的接口定义。好的系统架构离不开好的 API 设计,而一个设计不够完善的 API 则注定会导致系统的后续发展和维护非常困难。接下来,阿里巴巴研究员谷朴将给出建议,什么样的 API 设计是好的设计?好的设计该如何做? 作者简介:张瓅玶 (谷朴),阿里巴巴研究员,负责阿里云容器平台集群管理团队。本科和博士毕业于清华大学。 前言API 设计面临的挑战千差万别,很难有处处适用的准则,所以在讨论原则和最佳实践时,无论这些原则和最佳实践是什么,一定有适应的场景和不适应的场景。因此我们在下文中不仅提出一些建议,也尽量去分析这些建议在什么场景下适用,这样我们也可以有针对性地采取例外的策略。 为什么去讨论这些问题? API 是软件系统的核心,而软件系统的复杂度 Complexity 是大规模软件系统能否成功最重要的因素。但复杂度 Complexity 并非某一个单独的问题能完全败坏的,而是在系统设计尤其是API设计层面很多很多小的设计考量一点点叠加起来的(John Ousterhout老爷子说的Complexity is incremental【8】)。 成功的系统不是有一些特别闪光的地方,而是设计时点点滴滴的努力积累起来的。 范围本文偏重于一般性的API设计,并更适用于远程调用(RPC或者HTTP/RESTful的API),但是这里没有特别讨论RESTful API特有的一些问题。 另外,本文在讨论时,假定了客户端直接和远程服务端的API交互。在阿里,由于多种原因,通过客户端的 SDK 来间接访问远程服务的情况更多一些。这里并不讨论 SDK 带来的特殊问题,但是将 SDK 提供的方法看作远程 API 的代理,这里的讨论仍然适用。 API 设计准则:什么是好的 API在这一部分,我们试图总结一些好的 API 应该拥有的特性,或者说是设计的原则。这里我们试图总结更加基础性的原则。所谓基础性的原则,是那些如果我们很好地遵守了就可以让 API 在之后演进的过程中避免多数设计问题的原则。 提供清晰的思维模型 provides a good mental model 为什么这一点重要?因为 API 的设计本身最关键的难题并不是让客户端与服务端软件之间如何交互,而是设计者、维护者、API使用者这几个程序员群体之间在 API 生命周期内的互动。一个 API 如何被使用,以及API本身如何被维护,是依赖于维护者和使用者能够对该 API 有清晰的、一致的认识。这非常依赖于设计者提供了一个清晰易于理解的模型。这种状况实际上是不容易达到的。 就像下图所示,设计者心中有一个模型,而使用者看到和理解的模型可能是另一个模式,这个模式如果比较复杂的话,使用者使用的方式又可能与自己理解的不完全一致。 对于维护者来说,问题是类似的。 而好的 API 让维护者和使用者能够很容易理解到设计时要传达的模型。带来理解、调试、测试、代码扩展和系统维护性的提升 。 图片来源:https://medium.com/@copyconstruct/effective-mental-models-for-code-and-systems-7c55918f1b3e ...

May 9, 2019 · 4 min · jiezi

在 Angular 中引入 Jest 进行单元测试

在 Angular 中引入 Jest 进行单元测试为什么要从 Karma 迁移到 Jest用 Karma 在项目中遇到了坑最近新换了一个项目,去的时候项目已经做了两个月了,因为前期赶功能,没有对单元测试做要求,CI/CD 的时候也没有强制跑单元测试。所以虽然有用 Angular CLI 自动生成的测试文件,但是基本上都是测试不通过。项目做久了,人员变动多,新来的成员对之前的业务逻辑不清不楚,稍不注意就会破坏之前的功能;业务复杂了,随便增加或者修改一点点功能都可能引起不易被察觉的 BUG。作为一个敬业的开发,不上单元测试怎么行。所以,就有了一个修复已有单元测试的任务。修复已有测试文件的思路很简单:写个 TestingModule 把常用的依赖 mock 掉,再引入到需要的文件中就行了;不常用的依赖,在各自的文件中 mock 掉就好了。然而实际操作起来的时候,Karma 早早挖好坑等这了。有些测试文件单跑没有问题,整体跑得时候就报错,测试结果及其不稳定;karma 的报错信息又特别难读懂,很多时候根本定位不到到底是哪里出了问题。再加上 Karma 需要先把 Angular 应用编译之后再在浏览器中跑测试,整体时间也比较慢,修复的过程一直处于抓狂的边缘。整体测试跑起来的时候难以定位测试出错的定位,怎么办呢,那就让跑整个测试的时候各个文件之间也没有依赖可以单独跑好了,所以就想到了 Jest。实践证明,在 Angular 中, Jest 大法也非常好使。Karma 和 Jest 的对比前面也说过了,在修复测试的过程中,karma 遇到了各种各样的问题。归结起来大概就是:Karma 需要先把 Angular 应用整体编译之后再在浏览器中跑测试,跑测试的时间比较长;Karma 测试结果不稳定(很可能是因为异步操作引起的),单个文件和整体测试时的测试结果不一致;报错信息模糊不清,无法定位问题。特别是在有大量测试需要修复的情况下,难以定位问题的根本原因。那么对比而言,Jest 在上面这些方面都有很好的表现:不需要整体编译,可以单文件测试测试结果稳定报错清楚,易于定位问题除了这些,Jest 还有的好处有:开箱即用,基本算是全家桶,包含了测试需要的大部分工具:测试结构、断言、spies、mocks直接提供了测试覆盖率报告快照测试非常强大的模块级 mock 功能watch 模式仅仅测试和被修改文件相关的测试,速度非常快迁移第一步,你需要相关依赖包:npm install –save-dev jest jest-preset-angular @types/jest其中:jest – Jest 测试框架jest-preset-angular – jest 对于 angular 的一些通用的预设置@types/jest – Jest 的 typings第二步,你需要在 package.json 中对 Jest 进行配置:“jest”: { “preset”: “jest-preset-angular”, “setupFilesAfterEnv”: ["<rootDir>/src/setupJest.ts"]}其中,preset 声明了预设,setupFilesAfterEnv 配置了 Jest setup 文件的地址,可以包含多个文件,这里设置的是项目根目录下的 src/setupJest.ts。第三步,在 src 目录下创建上一步中设置的 setup 文件 setupJest.tsimport ‘jest-preset-angular’; // jest 对于 angular 的预配置import ‘./jestGlobalMocks’; // jest 全局的 mock第四步,在 src 目录下创建 jestGlobalMocks.ts 文件,并加入相关的全局的 mock,以下是一个例子:const mock = () => { let storage = {}; return { getItem: key => key in storage ? storage[key] : null, setItem: (key, value) => storage[key] = value || ‘’, removeItem: key => delete storage[key], clear: () => storage = {}, };};Object.defineProperty(window, ’localStorage’, {value: mock()});Object.defineProperty(window, ‘sessionStorage’, {value: mock()});Object.defineProperty(window, ‘getComputedStyle’, { value: () => [’-webkit-appearance’]});可以看到这个例子中 mock 了 window 上的对象,这是因为 jsdom 并没有实现所有的 window 上的对象和方法,所以有时我们需要自己给 window 打个补丁。在这里 mock localStorage 是可选的,如果我们在代码中并没有使用。但是 mock getComputedStyle 是必须的,因为 Angular 会检查它在哪个浏览器中执行。如果没有 mock getComputedStyle,我们的测试代码将无法执行。接下来,我们就可以在 package.json 的 script 中配置 test 的命令了:“test”: “jest”,“test:watch”: “jest –watch”,其中 test 只跑一次测试,test:watch 可以检测文件变化,跑当前有修改的文件的相关测试。此时,在命令行中运行测试命令,就应该能够顺利把测试跑起来并通过了。如果没有通过,可能是因为我们在 src/tsconfig.spec.json 中的 file 配置中有 test.js 的配置,这是 Karma 的 setup 文件,删掉这行配置并删除对应的文件,(src/tsconfig.app.json 中出现的 test.js 也可一并删除),重新跑一遍测试命令:npm run test至此,Jest 测试环境就算顺利搭建好了。如果你对代码有洁癖,接下来,你还可以删除 Karma 的相关代码,将测试全部转为 Jest。删除 Karma 相关代码删除相关依赖包(@types/jasmine @types/jasminewd2 jasmine-core jasmine-spec-reporter 因为在 e2e 测试中有使用所以不能删除):npm uninstall karma karma-chrome-launcher karma-coverage-istanbul-reporter karma-jasmine karma-jasmine-html-reporter删除文件 src/karma.config.js删除 angular.json 中 test 的配置src/tsconfig.spec.json 中 compilerOptions.type 的配置移除 jasmine, 加上 jest。至此,你已经删除了所有与 Karma 相关的代码。你甚至还能将测试断言换成 jest 的风格。查看最后生成的代码库和相关文件配置参考:Angular 6: “ng test” with Jest in 3 minutesTESTING ANGULAR FASTER WITH JEST ...

March 30, 2019 · 2 min · jiezi

PHPUnit实践二(生命周期)

本系列教程所有的PHPUnit测试基于PHPUnit6.5.9版本,Lumen 5.5框架PHPUnit测试一个文件类的生命周期理解PHPUnit加载机制(Lumen版)PHPUnit自动测试文件会自动加载引入(include file)PHPUnit去启动setUp方法,Lumen里重写了setUp,加载了bootstrap/app.phpapp.php加载了composer的autoload,借此你项目所有自动加载环境都有了,不过不包含tests目录至此我们引入了我们需要构建自己的自动加载类增加tests的自动加载我们需要给tests下的测试用例创建类似下面的结构├── BaseCase.php 重写过Lumen基类的测试基类,用于我们用这个基类做测试基类,后续会说明├── bootstrap.php tests自动加载文件├── Cases 测试用例目录│ └── Demo 测试模块│ ├── logs 日志输出目录│ ├── PipeTest.php PHPUnit流程测试用例│ ├── phpunit.xml phpunit配置文件xml│ └── README.md 本模块测试用例说明├── ExampleTest.php 最原始测试demo└── TestCase.php Lumen自带的测试基类tests自动加载文件代码<?php/** * 测试框架的自动加载测试文件类 * User: qikailin /error_reporting(E_ALL ^ E_NOTICE);require DIR . ‘/../vendor/autoload.php’;define(‘MY_TESTS_DIR_BASE’, realpath(dirname(FILE)));set_include_path(implode(PATH_SEPARATOR, array( WPT_TEST_DIR_BASE, get_include_path())));spl_autoload_register(function ($class) { $classFile = MY_TESTS_DIR_BASE . DIRECTORY_SEPARATOR . str_replace([“Test\”, “/”, “\”], ["", DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR], $class) . “.php”; if (file_exists($classFile)) { include_once $classFile; }}, true, false);phpunit.xml自动加载配置bootstrap文件<?xml version=“1.0” encoding=“UTF-8”?><phpunit bootstrap="../../bootstrap.php" convertErrorsToExceptions=“true” convertNoticesToExceptions=“false” convertWarningsToExceptions=“false” colors=“true”></phpunit>流程测试代码PipeTest 流程代码<?php/* * 测试类的每个测试方法都会运行一次 setUp() 和 tearDown() 模板方法(同时,每个测试方法都是在一个全新的测试类实例上运行的)。 * 另外,setUpBeforeClass() 与 tearDownAfterClass() 模板方法将分别在测试用例类的第一个测试运行之前和测试用例类的最后一个测试运行之后调用。 * 如果有需要共享的对象或变量,可以放在setUpBeforeClass,并设置为静态属性 * User: qikailin /namespace Test\Cases\Demo;use Test\BaseCase;class PipeTest extends BaseCase{ public static function setUpBeforeClass() { fwrite(STDOUT, METHOD . “\n”); } public function setUp() { fwrite(STDOUT, METHOD . “\n”); } /* * 测试方法的前置执行,setUp之后 / protected function assertPreConditions() { fwrite(STDOUT, METHOD . “\n”); } public function testOne() { fwrite(STDOUT, METHOD . “\n”); $this->assertTrue(true); } public function testTwo() { fwrite(STDOUT, METHOD . “\n”); // 两个交换下顺序可以看下效果 // 正常执行成功assert可以继续执行,失败的会跳出方法 $this->assertArrayHasKey(’d’, [’d’=>1, ’e’=>2]); $this->assertTrue(false); } public function testThree() { fwrite(STDOUT, METHOD . “\n”); $this->assertTrue(false); } public function testFour() { fwrite(STDOUT, METHOD . “\n”); } /* * 测试方法成功后的后置执行,tearDown之前 / protected function assertPostConditions() { fwrite(STDOUT, METHOD . “\n”); } public function tearDown() { fwrite(STDOUT, METHOD . “\n”); } public static function tearDownAfterClass() { fwrite(STDOUT, METHOD . “\n”); } /* * 不成功后拦截方法 * 必须重新抛出错误,如果不抛出错误,断言会当成成功了 */ public function onNotSuccessfulTest(\Throwable $e) { fwrite(STDOUT, METHOD . “\n”); // 必须重新抛出错误,如果不抛出错误,断言会当成成功了 throw $e; }}运行# 你可以把vendor/bin加入到环境变量PATHcd tests/Demo../../../vendor/bin/phpunit运行输出PHPUnit 6.5.9 by Sebastian Bergmann and contributors.Test\Cases\Demo\PipeTest::setUpBeforeClassTest\Cases\Demo\PipeTest::setUpTest\Cases\Demo\PipeTest::assertPreConditionsTest\Cases\Demo\PipeTest::testOneTest\Cases\Demo\PipeTest::assertPostConditionsTest\Cases\Demo\PipeTest::tearDown.Test\Cases\Demo\PipeTest::setUpTest\Cases\Demo\PipeTest::assertPreConditionsTest\Cases\Demo\PipeTest::testTwoTest\Cases\Demo\PipeTest::tearDownTest\Cases\Demo\PipeTest::onNotSuccessfulTestFTest\Cases\Demo\PipeTest::setUpTest\Cases\Demo\PipeTest::assertPreConditionsTest\Cases\Demo\PipeTest::testThreeTest\Cases\Demo\PipeTest::tearDownTest\Cases\Demo\PipeTest::onNotSuccessfulTestFTest\Cases\Demo\PipeTest::setUpTest\Cases\Demo\PipeTest::assertPreConditionsTest\Cases\Demo\PipeTest::testFourTest\Cases\Demo\PipeTest::assertPostConditionsTest\Cases\Demo\PipeTest::tearDownR 4 / 4 (100%)Test\Cases\Demo\PipeTest::tearDownAfterClassTime: 1.29 seconds, Memory: 6.00MBThere were 2 failures:1) Test\Cases\Demo\PipeTest::testTwoFailed asserting that false is true./xxx/tests/Cases/Demo/PipeTest.php:472) Test\Cases\Demo\PipeTest::testThreeFailed asserting that false is true./xxx/tests/Cases/Demo/PipeTest.php:53–There was 1 risky test:1) Test\Cases\Demo\PipeTest::testFourThis test did not perform any assertionsFAILURES!Tests: 4, Assertions: 4, Failures: 2, Risky: 1.Generating code coverage report in HTML format … done整理流程输出Test\Cases\Demo\PipeTest::setUpBeforeClassTest\Cases\Demo\PipeTest::setUpTest\Cases\Demo\PipeTest::assertPreConditionsTest\Cases\Demo\PipeTest::testOneTest\Cases\Demo\PipeTest::assertPostConditionsTest\Cases\Demo\PipeTest::tearDownTest\Cases\Demo\PipeTest::setUpTest\Cases\Demo\PipeTest::assertPreConditionsTest\Cases\Demo\PipeTest::testTwoTest\Cases\Demo\PipeTest::tearDownTest\Cases\Demo\PipeTest::onNotSuccessfulTestTest\Cases\Demo\PipeTest::setUpTest\Cases\Demo\PipeTest::assertPreConditionsTest\Cases\Demo\PipeTest::testThreeTest\Cases\Demo\PipeTest::tearDownTest\Cases\Demo\PipeTest::onNotSuccessfulTestTest\Cases\Demo\PipeTest::setUpTest\Cases\Demo\PipeTest::assertPreConditionsTest\Cases\Demo\PipeTest::testFourTest\Cases\Demo\PipeTest::assertPostConditionsTest\Cases\Demo\PipeTest::tearDownTest\Cases\Demo\PipeTest::tearDownAfterClass总结一个测试类文件,从setUpBeforeClass加载,且仅此加载一次每个测试方法都会走的过程:setUp->assertPreConditions->测试方法->[assert成功执行:assertPostConditions]->tearDown->[assert执行失败:onNotSuccessfulTest,且本方法需要抛出错误]本个测试类文件执行tearDownAfterClass结束参考PHPUnit 6.5 官方文档 ...

January 30, 2019 · 2 min · jiezi

React hooks实践

前言最近要对旧的项目进行重构,统一使用全新的react技术栈。同时,我们也决定尝试使用React hooks来进行开发,但是,由于React hooks崇尚的是使用(也只能使用)function component的形式来进行开发,而不是class component,因此,整个开发方式也会与之前产生比较大的差异。所以,我这里就积累了下实际项目中遇到的问题以及思考,看下能不能帮助大家少走弯路。正文接下来就直接进入正文。我会将项目中遇到的问题一一列举出来,并且给出解决方案。执行初始化操作的时机当我转到React hooks的时候,首先就遇到了这个问题:一般来说,业务组件经常会遇到要通过发起ajax请求来获取业务数据并且执行初始化操作的场景。在使用class component编程的时候,我们就可以在class component提供的生命周期钩子函数(比如componentDidMount, constructor等)执行这个操作。可是如果转到React hooks之后,function component里是没有这个生命周期钩子函数的,那这个初始化操作怎么办呢?总不能每次遇到这种场景都使用class component来做吧?解决方案:使用useEffect(想知道useEffect是什么的话,可以点击这里)useEffect,顾名思义,就是执行有副作用的操作,你可以把它当成componentDidMount, componentDidUpdate, and componentWillUnmount 的集合。它的函数声明如下useEffect(effect: React.EffectCallback, inputs?: ReadonlyArray<any> | undefined)那么,我们在实际使用中,我们就可以使用这个来执行初始化操作。举个例子import React, { useEffect } from ‘react’export function BusinessComponent() { const initData = async () => { // 发起请求并执行初始化操作 } // 执行初始化操作,需要注意的是,如果你只是想在渲染的时候初始化一次数据,那么第二个参数必须传空数组。 useEffect(() => { initData(); }, []); return (<div></div>);}需要注意的是,这里的useEffect的第二个参数必须传空数组,这样它就等价于只在componentDidMount的时候执行。如果不传第二个参数的话,它就等价于componentDidMount和componentDidUpdate做一些清理操作由于我们在实际开发过程中,经常会遇到需要做一些副作用的场景,比如轮询操作(定时器、轮询请求等)、使用浏览器原生的事件监听机制而不用react的事件机制(这种情况下,组件销毁的时候,需要用户主动去取消事件监听)等。使用class Component编程的时候,我们一般都在componentWillUnmount或者componentDidUnmount的时候去做清理操作,可是使用react hooks的时候,我们如何做处理呢?解决方案:使用useEffect第一个参数的返回值如果useEffect的第一个参数返回了函数的时候,react会在每一次执行新的effects之前,执行这个函数来做一些清理操作。因此,我们就可以使用它来执行一些清理操作。例子:比如我们要做一个二维码组件,我们需要根据传入的userId不断轮询地向后台发请求查询扫描二维码的状态,这种情况下,我们就需要在组件unmount的时候清理掉轮询操作。代码如下:import React, { useEffect } from ‘react’export function QRCode(url, userId) { // 根据userId查询扫描状态 const pollingQueryingStatus = async () => { } // 取消轮询 const stopPollingQueryStatus = async() => { } useEffect(() => { pollingQueryingStatus(); return stopPollingQueryStatus; }, []); // 根据url生成二维码 return (<div></div>)}这样的话,就等价于在componentWillUnmount的时候去执行清理操作。但是,有时候我们可能需要执行多次清理操作。还是举上面的例子,我们需要在用户传入新的userId的时候,去执行新的查询的操作,同时我们还需要清除掉旧的轮询操作。想一下怎么做比较好。其实对这种情况,官方也已经给出了解决方案了,useEffect的第二个参数是触发effects的关键,如果用户传入了第二个参数,那么只有在第二个参数的值发生变化(以及首次渲染)的时候,才会触发effects。因此,我们只需要将上面的代码改一下:import React, { useEffect } from ‘react’export function QRCode(url, userId) { // 根据userId查询扫描状态 const pollingQueryingStatus = async () => { } const stopPollingQueryStatus = async() => { } // 我们只是将useEffect的第二个参数加了个userId useEffect(() => { pollingQueryingStatus(); return stopPollingQueryStatus; }, [userId]); // 根据url生成二维码 return (<div></div>)}我们只是在useEffect的第二个参数数组里,加入了一个userId。这样的话,userId的每一次变化都会先触发stopPollingQueryStatus,之后再执行effects,这样就可以达到我们的目的。useState与setState的差异react hooks使用useState来代替class Component里的state。可是,在具体开发过程中,我也发现了一些不同点。useState介绍可以点击这里在setState的时候,我们可以只修改state中的局部变量,而不需要将整个修改后的state传进去,举个例子import React, { PureComponent } from ‘react’;export class Counter extends React.Component { constructor(props) { super(props); this.state = { count: 0, name: ‘cjg’, age: 18, } } handleClick = () => { const { count } = this.state; // 我们只需要传入修改的局部变量 this.setState({ count: count + 1, }); } render() { return ( <button onClick={this.handleClick}></button> ) }}而使用useState后,我们修改state必须将整个修改后的state传入去,因为它会直接覆盖之前的state,而不是合并之前state对象。import React, { useState } from ‘react’;export function Count() { const [data, setData] = useState({ count: 0, name: ‘cjg’, age: 18, }); const handleClick = () => { const { count } = data; // 这里必须将完整的state对象传进去 setData({ …data, count: count + 1, }) }; return (<button onClick={handleClick}></button>)}减少不必要的渲染在使用class Component进行开发的时候,我们可以使用shouldComponentUpdate来减少不必要的渲染,那么在使用react hooks后,我们如何实现这样的功能呢?解决方案:React.memo和useMemo对于这种情况,react当然也给出了官方的解决方案,就是使用React.memo和useMemo。React.memoReact.momo其实并不是一个hook,它其实等价于PureComponent,但是它只会对比props。使用方式如下(用上面的例子):import React, { useState } from ‘react’;export const Count = React.memo((props) => { const [data, setData] = useState({ count: 0, name: ‘cjg’, age: 18, }); const handleClick = () => { const { count } = data; setData({ …data, count: count + 1, }) }; return (<button onClick={handleClick}>count:{data.count}</button>)});useMemouseMemo它的用法其实跟useEffects有点像,我们直接看官方给的例子function Parent({ a, b }) { // Only re-rendered if a changes: const child1 = useMemo(() => <Child1 a={a} />, [a]); // Only re-rendered if b changes: const child2 = useMemo(() => <Child2 b={b} />, [b]); return ( <> {child1} {child2} </> )}从例子可以看出来,它的第二个参数和useEffect的第二个参数是一样的,只有在第二个参数数组的值发生变化时,才会触发子组件的更新。总结一开始在从class component转变到react hooks的时候,确实很不适应。可是当我习惯了这种写法后,我的心情如下:当然,现在react hooks还是在alpha阶段,如果大家觉得不放心的话,可以再等等。反正我就先下手玩玩了哈哈哈。本文地址在->本人博客地址, 欢迎给个 start 或 follow ...

January 27, 2019 · 2 min · jiezi

PostgreSQL的实践一:初识

简介和认知发音post-gres-q-l服务(server)一个操作系统中可以启动多个postgres服务。每个服务由多个进程组成,为首的进程名为postmaster。每个服务要占用一个端口,多个服务不能共享端口。每个服务都有一个data目录用于存放数据,目录不允许修改,否则会破坏数据库,并且无法修复。服务使用4字节长的内部事务标识符,即时发生重叠后仍然继续使用,这会导致问题,所以需要定期进行VACUUM操作。数据库(database)一个服务中可以拥有多个数据库。数据库默认是任何用户可连接的,创建好后需要修改相应的权限。数据库之间的数据是隔离的,不能进行联表。数据库默认的数据块大小为8192。模式(schema)一个数据库中可以有多个模式,模式相当于表的命名空间,类似于mysql中的database,可以使用带模式的完整名称来访问或者创建对象。不同模式之间的表是可以联表查询的。可以通过对用户设置search_path参数来指定默认搜索的模式。表(table)一个模式中可以有多张表。表是由多个关系元素组成的,大字段数据放在另一个名为TOAST的表中,每张表都有一个TOAST表和TOAST索引。用双引号括起来的表和没用双引号括起来的表是不一样的,即使名字一样。双引号括起来的表区分大小写,没用双引号括起来的表不区分大小写。列(column)每张表都由许多列组成,每一列有一个列名、类型、默认值等属性,用来存储每一条记录中的各种值。文本类型统一由一种数据类型存储,支持长度从1B到1G,经过优化,存储少的时候很高效,存储多的时候会自动管理和压缩。自增类型serial本质上就是整数,通过创建并关联到一个SEQUENCE类型的对象来记录自增值。表空间(tablespace)默认情况下,所有的数据都会放在postgres指定的data目录下,通过定义表空间,可以让postgres将数据存放在不同的设备上。表空间是通过软链接来实现的。建议为每个数据库设立一个单独的表空间,尤其是不同数据库中有同名的模式或者表的时候。postgres=# CREATE TABLESPACE tbs LOCATION ‘/usr/local/tbs’;视图(view)视图本质上是预定义好的一个sql查询,以一张表的形式给出,在每次调用时都会执行相应的sql查询。postgres=# CREATE VIEW view AS SELECT * FROM tb;当视图足够简单的时候,postgres是支持视图更新的,相应的更新会传递到相应的表中。还可以使用INSTEAD OF触发器或者规则来实现视图更新,请参考具体的操作手册。物化视图可以预先将数据查询出来,这样调用的时候就不必反复查询了,更新需要手动更新。postgres=# CREATE MATERIALIZED VIEW view AS SELECT * FROM tb;postgres=# REFRESH MATERIALIZED VIEW view;行(row)行即表中的一条数据。postgres中每个行都有一个行版本,而且还有两个系统列xmin和xmax,分别标示这个行被创建和删除的事务。删除时,设置xmax为删除事务号,不会实际执行删除。UPDATE操作被认为是紧跟INSERT操作后的DELETE操作。索引(index)索引可以用来给表添加约束或者提高查询速度。在涉及高比例插入删除的表中,会造成索引膨胀,这时候可以重建索引。reindexdb创建CONCURRENTLY索引时不会持有全表锁,这条指令分成两个步骤,第一部分创建索引并标记为不可用,这时候INSERT、UPDATE、DELETE操作已经开始维护索引了,但是查询不能使用索引。建立完毕后才会被标记为可用。postgres=# CREATE CONCURRENTLY INDEX index ON tb(id);可以手工设置索引的可用性。UPDATE pg_index SET indisvalid = false WHERE indexrelid = index::regclass;pgsql 中表空间/数据库/模式 的关系表空间是物理结构,同一表空间下可以有多个数据库数据库是逻辑结构,是表/索引/视图/存储过程的集合,一个数据库下可以有多个schema模式是逻辑结构,是对数据库的逻辑划分安装# vist https://www.postgresql.org/download/# Interactive installer by EnterpriseDB -> 选择10.5版本的Windows x86-64下载1. 一路的next安装,当然你可以自己选择安装的目录2. 提示输入postgres帐号的密码,你可以根据自己的喜好,设置一个,比如这里我设置了:1234562. 提示安装插件扩展,取消即可,暂时不需要安装psql客户端简单实用连接# $MY_POSTGRES_PATH = D:\PostgreSQL; 这个环境参数代表我安装的Postgresql服务器所在的目录# $MY_POSTGRES_PATH/bin/psql -U postgres$MY_POSTGRES_PATH/bin/scripts/runpsql# 依次默认回车,如果有需要调整参数,你可以自定义# 输入123456#outputServer [localhost]:Database [postgres]:Port [5432]:Username [postgres]:用户 postgres 的口令:psql (10.5)输入 “help” 来获取帮助信息.postgres=## 输入help得到以下提示postgres=# help您正在使用psql, 这是一种用于访问PostgreSQL的命令行界面键入: \copyright 显示发行条款 \h 显示 SQL 命令的说明 ? 显示 pgsql 命令的说明 \g 或者以分号(;)结尾以执行查询 \q 退出postgres=## \l 查看已存在的数据库postgres-# \l 数据库列表 名称 | 拥有者 | 字元编码 | 校对规则 | Ctype | 存取权限———–+———-+———-+—————————————————–+—————————————————–+———————– postgres | postgres | UTF8 | Chinese (Simplified)_People’s Republic of China.936 | Chinese (Simplified)_People’s Republic of China.936 | template0 | postgres | UTF8 | Chinese (Simplified)_People’s Republic of China.936 | Chinese (Simplified)_People’s Republic of China.936 | =c/postgres + | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | Chinese (Simplified)_People’s Republic of China.936 | Chinese (Simplified)_People’s Republic of China.936 | =c/postgres + | | | | | postgres=CTc/postgres(3 行记录)# 我们可以发现默认存在postgres、template0和template1数据库,templateX是模板数据库# template1为可修改模版库,template0为不可修改模版库创建数据库postgres=# create database testdb;# CREATE DATABASE# \c = \connectpostgres=# \c testdb;# 您现在已经连接到数据库 “testdb”,用户 “postgres”.创建表# 查看表testdb=# \d# Did not find any relations.# 创建表testdb=# create table test1(id int primary key, name varchar(50));# CREATE TABLEtestdb=# \d 关联列表 架构模式 | 名称 | 类型 | 拥有者———-+——-+——–+———- public | test1 | 数据表 | postgres(1 行记录)# 架构模式(schema)我们后续会讲,暂时你可以先理解为一个数据库逻辑分类的概念,默认创建数据库都会有一个public的schema常规显示设置# 设置显示查询时间\timing on# 设置border的边框内外都有\pset border 2# 查看编码\encoding# 设置编码\encoding UTF8# 开启扩展显示,纵向打印每列数据\x# 例子:testdb=# select * from test1;+-[ RECORD 1 ]-+| id | 1 || name | qkl |+——+—–+# 设置命令执行的真正sql:on打开 off关闭\set ECHO_HIDDEN on\set ECHO_HIDDEN off# 案例:testdb=# \set ECHO_HIDDEN ontestdb=# \d********* 查询 *********SELECT n.nspname as “Schema”, c.relname as “Name”, CASE c.relkind WHEN ‘r’ THEN ’table’ WHEN ‘v’ THEN ‘view’ WHEN ’m’ THEN ‘materialized view’ WHEN ‘i’ THEN ‘index’ WHEN ‘S’ THEN ‘sequence’ WHEN ’s’ THEN ‘special’ WHEN ‘f’ THEN ‘foreign table’ WHEN ‘p’ THEN ’table’ END as “Type”, pg_catalog.pg_get_userbyid(c.relowner) as “Owner"FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespaceWHERE c.relkind IN (‘r’,‘p’,‘v’,’m’,‘S’,‘f’,’’) AND n.nspname <> ‘pg_catalog’ AND n.nspname <> ‘information_schema’ AND n.nspname !~ ‘^pg_toast’ AND pg_catalog.pg_table_is_visible(c.oid)ORDER BY 1,2;**************************关联列表+-[ RECORD 1 ]——–+| 架构模式 | public || 名称 | test1 || 类型 | 数据表 || 拥有者 | postgres |+———-+———-+常用命令testdb-# ?一般性 \copyright 显示PostgreSQL的使用和发行许可条款 \crosstabview [COLUMNS] 执行查询并且以交叉表显示结果 \errverbose 以最冗长的形式显示最近的错误消息 \g [文件] or; 执行查询 (并把结果写入文件或 |管道) \gexec 执行策略,然后执行其结果中的每个值 \gset [PREFIX] 执行查询并把结果存到psql变量中 \gx [FILE] as \g, but forces expanded output mode \q 退出 psql \watch [SEC] 每隔SEC秒执行一次查询帮助 ? [commands] 显示反斜线命令的帮助 ? options 显示 psql 命令行选项的帮助 ? variables 显示特殊变量的帮助 \h [名称] SQL命令语法上的说明,用显示全部命令的语法说明查询缓存区 \e [FILE] [LINE] 使用外部编辑器编辑查询缓存区(或文件) \ef [FUNCNAME [LINE]] 使用外部编辑器编辑函数定义 \ev [VIEWNAME [LINE]] 用外部编辑器编辑视图定义 \p 显示查询缓存区的内容 \r 重置(清除)查询缓存区 \w 文件 将查询缓存区的内容写入文件输入/输出 \copy … 执行 SQL COPY,将数据流发送到客户端主机 \echo [字符串] 将字符串写到标准输出 \i 文件 从文件中执行命令 \ir FILE 与 \i类似, 但是相对于当前脚本的位置 \o [文件] 将全部查询结果写入文件或 |管道 \qecho [字符串] 将字符串写到查询输出串流(参考 \o)Conditional \if EXPR begin conditional block \elif EXPR alternative within current conditional block \else final alternative within current conditional block \endif end conditional block资讯性 (选项: S = 显示系统对象, + = 其余的详细信息) \d[S+] 列出表,视图和序列 \d[S+] 名称 描述表,视图,序列,或索引 \da[S] [模式] 列出聚合函数 \dA[+] [PATTERN] list access methods \db[+] [模式] 列出表空间 \dc[S+] [PATTERN] 列表转换 \dC[+] [PATTERN] 列出类型强制转换 \dd[S] [PATTERN] 显示没有在别处显示的对象描述 \dD[S+] [PATTERN] 列出共同值域 \ddp [模式] 列出默认权限 \dE[S+] [PATTERN] 列出引用表 \det[+] [PATTERN] 列出引用表 \des[+] [模式] 列出外部服务器 \deu[+] [模式] 列出用户映射 \dew[+] [模式] 列出外部数据封装器 \df[antw][S+] [模式] 列出[只包括 聚合/常规/触发器/窗口]函数 \dF[+] [模式] 列出文本搜索配置 \dFd[+] [模式] 列出文本搜索字典 \dFp[+] [模式] 列出文本搜索解析器 \dFt[+] [模式] 列出文本搜索模版 \dg[S+] [PATTERN] 列出角色 \di[S+] [模式] 列出索引 \dl 列出大对象, 功能与\lo_list相同 \dL[S+] [PATTERN] 列出所有过程语言 \dm[S+] [PATTERN] 列出所有物化视图 \dn[S+] [PATTERN] 列出所有模式 \do[S] [模式] 列出运算符 \dO[S+] [PATTERN] 列出所有校对规则 \dp [模式] 列出表,视图和序列的访问权限 \drds [模式1 [模式2]] 列出每个数据库的角色设置 \dRp[+] [PATTERN] list replication publications \dRs[+] [PATTERN] list replication subscriptions \ds[S+] [模式] 列出序列 \dt[S+] [模式] 列出表 \dT[S+] [模式] 列出数据类型 \du[S+] [PATTERN] 列出角色 \dv[S+] [模式] 列出视图 \dx[+] [PATTERN] 列出扩展 \dy [PATTERN] 列出所有事件触发器 \l[+] [PATTERN] 列出所有数据库 \sf[+] FUNCNAME 显示一个函数的定义 \sv[+] VIEWNAME 显示一个视图的定义 \z [模式] 和\dp的功能相同格式化 \a 在非对齐模式和对齐模式之间切换 \C [字符串] 设置表的标题,或如果没有的标题就取消 \f [字符串] 显示或设定非对齐模式查询输出的字段分隔符 \H 切换HTML输出模式 (目前是 关闭) \pset [NAME [VALUE]] set table output option (NAME := {border|columns|expanded|fieldsep|fieldsep_zero| footer|format|linestyle|null|numericlocale|pager| pager_min_lines|recordsep|recordsep_zero|tableattr|title| tuples_only|unicode_border_linestyle| unicode_column_linestyle|unicode_header_linestyle}) \t [开|关] 只显示记录 (目前是 关闭) \T [字符串] 设置HTML <表格>标签属性, 或者如果没有的话取消设置 \x [on|off|auto] 切换扩展输出模式(目前是 关闭)连接 \c[onnect] {[DBNAME|- USER|- HOST|- PORT|-] | conninfo} 连接到新数据库(当前是"testdb”) \conninfo 显示当前连接的相关信息 \encoding [编码名称] 显示或设定客户端编码 \password [USERNAME] 安全地为用户更改口令操作系统 \cd [目录] 更改目前的工作目录 \setenv NAME [VALUE] 设置或清空环境变量 \timing [开|关] 切换命令计时开关 (目前是 开启) ! [命令] 在 shell中执行命令或启动一个交互式shell变量 \prompt [文本] 名称 提示用户设定内部变量 \set [名称 [值数]] 设定内部变量,若无参数则列出全部变量 \unset 名称 清空(删除)内部变量大对象 \lo_export LOBOID 文件 \lo_import 文件 [注释] \lo_list \lo_unlink LOBOID 大对象运算 ...

November 5, 2018 · 4 min · jiezi

Go Defer 高级实践

defer 是一个用起来非常简单的特性。它的实现原理也不复杂。本文主要介绍这个特性在实际项目中的利弊以及建议。为什么要用 defer任何一个特性都有它的设计初衷,主要是被用来解决什么问题的,任何一个特性也都有它合适和不合适出现的地方,我们清楚地了解并正确合理地使用,是非常重要的。优势提高安全性、健壮性让代码更优雅劣势可读性、可维护性(注意:用 defer 当然肯定比不用有一定的性能开销,但我们可以忽略,因为影响确实很小。 换句话说,绝大部分情况下,考虑是否使用 defer 时,性能开销不应该是首先考虑的因素。但是!如果你的代码是微秒级别的,那还是要评估后再使用)defer 怎么用官方文档,告诉你 defer 的基本用法几乎所有其他文章里说 defer 如何如何有坑,defer 需要注意什么等等。。都是官方文档上讲到的三点,在此就不赘述了。下面我分成三部分,建议使用、中立和不建议。建议使用 是官方 src 里都在用的,而且也是 defer 的设计初衷。中立 是工程实践中总结出来,平衡了代码优雅和可读性、可维护性后的结果。不建议 是弊大于利,得不偿失的用法,主要影响的就是降低可读性,可维护性。建议使用Recoverdefer func() { if r := recover(); r != nil { fmt.Println(“Recovered”, r) }}()资源回收各种资源的使用,如果在用完之后不 close,就会造成资源的泄露,可能会严重影响程序运行,甚至造成程序死掉网络 I/Oc, err := Dial(“udp”, raddr)if err != nil { return err}defer c.Close()文件 I/Of, err := os.Open(filename)if err != nil { return}defer f.Close()channel 关闭fd, _ := os.Open(“txt”)errc := make(chan error, 1)// 要记得关闭,不然当函数返回了,就等于泄露了defer close(errc) var buf [1]byten, err := fd.Read(buf[:1])if n == 0 || err != nil { errc <- fmt.Errorf(“read byte = %d, err = %v”, n, err)}避免死锁type A struct { t int sync.Mutex}func main() { a := new(A) for i := 0; i < 2000; i++ { go a.incr() } time.Sleep(500 * time.Millisecond) // 此处用 sleep 简单模拟等待同步,实际这样写不严谨,可用 waitGroup、channel 等 fmt.Println(a.t)}func (a *A) incr() { a.Lock() defer a.Unlock() // 模拟 … 一堆逻辑 // 然后 … 中间有好几个 return 出口 // 如果我们不用 defer,就要在每个 return 都写上 a.Unlock,不然就可能会造成死锁 a.t++}中立函数返回时的打点记日志这里可能稍微有一些复杂,我稍微讲一下第一步,会先执行 log(“do”) 调用 log 函数传入参数 “do”第二步,log 函数执行函数体即 start := time.Now() fmt.Printf(“enter %s\n”, msg)两行,然后给调用方 do 函数返回一个 func()第三步,这个 func() 被放到 defer 里,等到 do 函数返回时才会执行。func main() { do()}func do() { defer log(“do”)() // … 一些逻辑 time.Sleep(1 * time.Second)}func log(msg string) func() { start := time.Now() fmt.Printf(“enter %s\n”, msg) return func() { fmt.Printf(“exit %s (%s)”, msg, time.Since(start)) }}错误处理因为 go 自带的比较恶心的 err != nil 的判断,业务逻辑中可能会有大量的这种代码,而我们又要对出错进行一个统一的处理的时候,可以用。数据库事务的回滚操作tx, err := db.Begin()if err != nil { return err}defer func() { if err != nil { tx.Rollback() }}()// … 中间会发生多个数据库操作 …// 提交,那么在提交之前发生的任何错误,返回时都可利用之前注册的 defer 进行回滚tx.Commit()不建议不建议的用法就不给出代码示例了,怕你看了错误的代码示例反而记住了,就不好了。下面只说不建议的用法场景。不要直接在循环中使用 deferdefer 是后定义的先执行,和栈类似。如果在循环中调用 defer,可能会导致堆积了很多 defer,在循环结束后才会执行。这中间如果有任何一个 defer 失败了怎么办?多个 defer 执行的内容有没有依赖关系和冲突?所以,除非万不得已,不要给自己增加复杂度。不这么用就好了。不要在 defer 中传入体积很大的参数因为编译器的很多优化对它都不起作用,所以尽量不要传入体积很大的参数,当然我觉得也应该没有多少人会传入一堆参数来用 defer 的。不要用 receiver 调用 defer因为 receiver 是当做第一个参数传给调用函数的,也是值传递,除非你能时刻明确注意 receiver 是否是一个指针,否则最好不要用 defer,不然可能无法得到你想要的结果。未完待续。。。defer 原理简述defer 源码实现的位置:runtime/panic.go看到这知道我在建议使用中第一个就写 recover 是为什么了吧。这个特性最初的目的就是给 recover 用的。编译器会把 defer 关键字转化为对此函数的调用:func deferproc(siz int32, fn *funcval)然后当原函数 return 时,会调用:func deferreturn(arg0 uintptr)看,它只有一个参数,就是 arg0,也就是 代码中 defer 后面跟着的函数。明显的,只有函数体本身会延迟执行,函数的参数在注册 defer 之前就已经执行完了。结语老老实实写代码,不要总想玩魔法。 ...

October 13, 2018 · 2 min · jiezi