技术团队运用度量驱动开发提升质量:策略与实践

Published / by 高成 / Leave a Comment

背景介绍

公司要发展是为了保持竞争力、实现可持续发展并满足市场需求。随着市场环境的不断变化,公司需要不断创新、拓展业务范围、提高产品质量和服务水平,以适应不断变化的市场需求和客户需求。只有不断发展的公司才能在市场中立于不败之地,实现可持续发展。而业务是公司发展的基础和核心,公司通过不断拓展和优化业务来实现发展目标。
随着业务多模式发展,二手车业务已经从相对简单的业务逐步转变为包含交易业务交易、O2O、信息业务等。随着业务的发展,用户在业务中的生命周期获得了延长,用户端和商家端在业务上结合得越发紧密。在此基础上,还有新旧业务功能持续集成,以此来产生协同效应。越来越多的业务流程也导致了管控难度的提升以及流程上下游之间衔接点的增多。在这个业务发展的背景下,技术系统在支撑业务功能迭代时发现,由于业务的广度和深度的增加,技术系统在实现业务目标时,服务与服务之间的调用链路增长,关系增多,业务目标服务与服务之间的转化难度也在逐步提升,技术系统领域的复杂度也产生了新的增长。这些技术系统的问题会直接反映在业务目标的转化上,体现在是否更快速、更高效。

意义价值

技术团队的目标是开发新功能和保障技术系统稳定运行。业务的实现严重依赖于技术系统的运行状况,而越是复杂的技术系统,就越需要技术团队来掌控其运行状态。只有当技术团队很好地掌握了技术系统的运行状况时,才能助力业务目标的实现。提高技术团队的掌控能力需要深入洞察技术系统的运行状态。随着技术系统的复杂度不断提高,技术团队面临着三个关键性洞察力问题。从业务视角来看,技术层面的监控系统缺乏对业务的深度监测和评估,链路监控无法实现对业务转化链路的串联监测,而仅有的基础资源类监控指标无法反映业务结果。

业务部门的技术团队作为为商业侧服务的技术团队,其目标都是支撑业务实现商业价值。技术团队的核心问题在于提升商业转化路径上各个业务节点的技术质量。技术团队在技术层面需要提升对技术系统的洞察力,在业务层面需要确保商业转化路径的质量。上述两个方面的诉求归根结底都与技术系统的质量相关,既横向保障业务在商业转化路径上的质量,又纵向保障技术系统在系统调用链路上的质量。综上所述,技术团队的任务是实现商业价值,而商业价值的实现路径需要有很好的质量保障。技术团队需要解决的问题是提升系统的洞察力,以夯实实现商业价值的基础。

实践操作

实现商业价值

那么业务侧的技术团队如何实现商业价值?技术团队可以通过优化业务流程、开发和实施高效的业务流程来提高公司的整体运营效率。也可以通过创新产品或服务、研发新技术或新产品来满足市场需求,从而带来商业价值,或者通过降低成本、优化技术方案来降低公司的运营成本等多种方式来在实现商业价值中做出贡献。通过拆解技术团队的日常工作,技术团队在实现商业价值中的核心是两个事项:编写代码和运行代码,然后实现新功能、改进现有功能、修复错误、提高性能或降低成本等。所有这些产生商业价值的事情只有在代码运行时才能提供,而不是在编写时就可以提供。因为即使代码设计模式适用、代码注释详尽、数据算法高效,如果没有运行,对于业务而言仍然没有实现任何商业价值。运行中的代码才是有商业价值的。因此,为了为业务提供最大价值,技术团队需要尽可能深入地了解代码运行时的状态,而技术系统的度量指标通常是实现这一要求的唯一方法。

行业解决方案

服务于业务侧的技术团队,希望能够通过对技术系统的持续改进在实现商业价值中做出更多的贡献。结合团队的诉求和现实情况,行业内有各种各样的监控系统,能够实现技术系统端到端的监控,比如Prometheus等。同时,汽车之家内部也有一些自研的监控系统,基本能够实现全覆盖的监控。然而,技术系统的持续改进与带来商业价值之间总是缺乏一个有效的链接。我们逐渐认识到单纯部署一个或是几个监控系统不能解决我们的诉求,我们需要的是一种能够建立在基于数据的决策思想之上的方法,旨在提高软件质量、性能和可维护性,在整个软件开发生命周期中持续收集、分析和利用各种度量和指标,通过与业务侧深度协作,通过有益的决策来推动持续改进。这与度量驱动开发(Metrics-Driven Development,简称MDD)的理念不谋而合。
度量驱动开发主张整个应用开发过程由指标度量驱动,通过实时度量指标来驱动快速、精确和细粒度的软件迭代。度量驱动开发的理念,不但可以让技术团队实时感知技术系统的状态,及时跟踪定位并解决问题,而且可以帮助业务和运维团队一起关注相关的业务指标。

度量驱动开发(Metrics-Driven Development)的理念理早是在2011年3月12日Etsy公司举办的一次技术交流会上,由Etsy核心平台部负责人Mike Brittain提出的。

应用可观测性

业界对于度量驱动开发有许多应用的案例和实践,来自Gartner的《2023年重要战略技术趋势》中的“应用可观测性”也介绍了类似度量驱动开发一致的理念。

“应用可观测性是指,以高度协调和整合的方式 在业务职能部门、应用和运维(I&O)团队中应用可观测的数据,尽可能缩短行动与响应之间的延迟,实现业务决策的主动规划。”
引用

Prometheus

Prometheus官网的宣传标语是From metrics to insight(从指标度量到洞察力)。

度量驱动开发

度量驱动开发的理念是需求阶段就考虑设置关键指标监控项,随着应用上线,通过指标了解系统状态,通过对现状的数字化和可视化,帮助业务对未来进行规划和预测,进而实现业务改善。而且度量驱动开发是一种文化的纽带,对于敏捷开发、持续集成、持续交付,以及各个职能岗位提升合作共赢的意识具有很大的帮助。

  • 对业务而言,可以实时掌控业务各项指标,通过数据做出决策。
  • 对研发而言,可以实时感知应用各项指标、聚焦应用优化。
  • 对运维而言,可以实时感知系统各项指标、快速定位问题。

度量驱动开发可使所有可以测量的东西都得到量化和优化,进而为整个开发过程带来可见性,帮助相关人员快速、准确地做出决策,并在发生错误时立即发现问题并修复。我们希望通过感知技术系统的运行状态,并且不断根据运行时的数据提供改进策略,将上线、监控、调试、故障调查及优化等纳入设计阶段,而不是等到系统部署后再去补充。相对于通过制定各种复杂、严格的研发规定,以及各种评审会议来确保技术系统的安全可靠、稳定运行,度量驱动开发的理念的特别之处在于,通过采集必要的监控信息,通过持续交付方式进行快速迭代并进行反馈和修正,所有决定都是基于对不断变化的情况的观察做出的。

团队实践探索

技术团队在采用度量驱动开发的实践探索过程中,总体分为4个阶段,首先,依据业务的范围进一步圈定核心领域。其次,通过核心领取构建度量指标体系。再次,通过对于度量指标的监控协同业务侧推动部分指标的改善,我们在此采用了最小可行产品(Minimum Viable Product,MVP)的策略,通过构建具有最少功能的版本,尽早地推出产品以测试反馈并验证概念的可行性。最后在验证效果后建立可视化的技术系统来推动整体的实践探索更具易用性、扩展性的落地和发展。

度量驱动开发那么首先需要解决的问题就是度量,也就是度量指标体系的构建,回顾探索实践的过程,在实践探索的过程中遇到的困难的也是度量指标体系的构建。度量指标体系的构建我们的目标是做到覆盖尽可能全面的覆盖,我们对于全面覆盖总结为横向和纵向2个方向上的覆盖。首先,横向需要满足业务的广度尽可能的纳入更多的核心关键业务,其次,纵向需要将业务-技术纵深进行深入的挖掘覆盖尽可能多的核心关键技术系统。

团队在度量指标体系的构建中,围绕业务流程的服务树,通过业务流程中各个关键节点的指标的下钻和穿透到极致,再通过参考Google SRE中提出的系统监控的四个黄金指标,构造业务-技术的全覆盖度量指标体系。

  • 延迟(Latency):衡量服务请求所需时间。例如,从技术视角所关注的HTTP请求平均耗时,而在业务视角下为用户完成下单操作的所需时长。
  • 流量(Traffic):衡量服务的容量需求。例如,从技术视角下每秒处理的HTTP请求数或者数据库系统的事务数量,业务视角下用户完成下单的数量。
  • 错误(Errors):衡量服务错误发生的速率。例如,技术视角下HTTP 500错误数等显式失败,返回错误内容或无效内容等隐式失败,业务视角下用户下单失败数量等。
  • 饱和度(Saturation):衡量当前服务的饱和度。例如,技术视角下内存、CPU、I/O、磁盘使用量,业务视角下的任务的完成率、优惠卷的使用量等。

技术在系统建设阶段完成了一个覆盖业务上用户端到商家端,技术上客户端到服务端的全景监控系统的建设,核心功能包括数据可视化、业务链路定制和监控预警。首先,我们复用公司的数据处理能力,包括数据收集、清洗、转换和存储等基础数据处理服务,通过复用它们,我们能够迅速获取数据处理能力,确保数据的准确性和一致性。另外,我们通过接入前端性能监控、云监控以及质量罗盘等监控系统,我们实现对整个技术系统的实时监控。在系统建设的技术选型上,我们选择了低代码平台作为开发工具。低代码平台提供了可视化开发环境,减少了开发工作的复杂性,不仅加快了构建和迭代速度,还提高了系统的灵活性和可扩展性。全景监控系统的建设不仅有助于团队更好地理解和管理其业务和技术系统,还为未来的创新和扩展奠定了坚实的基础。

实践成果

完成度量指标体系构建

完成基于业务的度量指标体系构建,完成设计近400个相关数据指标,实现了业务流程和技术系统的全面覆盖,具有重要意义。这一成果为业务提供了全面的数据洞察,帮助业务和技术人员更好地理解业务进展和技术系统,从而做出更明智的战略决策、提高效率、优化资源分配、改善客户体验,最终实现竞争优势和可持续增长。这些指标不仅提供了深刻的业务洞察,还为数据驱动的决策和创新奠定了坚实的基础。

形成改善的度量指标

商业价值提升,用户买卖车信息的处理效率提升240%,用户卖车信息的从车辆信息的提交再到将车辆信息通知商家进行处理这其中要经历很多业务流程以及技术系统,通过对车辆信息数据处理流程时长的监测发现问题点,通过与业务方协作的方式,改进车辆信息数据的处理流程,提高了数据留转与处理的时效,通过技术系统的改善提升了业务的运转效率,提升了商业价值。
商业价值挽回,拦截异常车况报告解析订单2000单,在车况报告解析积压和延时的及时预警发现问题点,通过对异常情况的的及时跟进处理拦截异常订单,实现商业价值的挽回。

未来展望

度量驱动开发(Metric-Driven Development,MDD)在软件工程领域扮演着关键的角色。它强调了度量数据在软件开发过程中的重要性,这些度量数据可以是关于代码质量、性能、可维护性、进度等各个方面的信息。首先,度量驱动开发有助于质量的改进。通过定期收集和分析度量数据,技术团队可以更好地了解软件质量的状态。这包括了解代码质量、性能表现、可维护性等各个方面。当度量数据揭示出问题或潜在的缺陷时,团队可以采取措施来改进质量,确保软件达到高标准。其次,度量数据可以用于目标设定。技术团队可以根据度量数据来设定明确的开发目标。例如,他们可以使用性能度量来设定性能目标,代码质量度量来设定代码质量标准。将这些目标加入到技术团队开发过程中的指导原则,有助于确保项目朝着期望的方向前进。此外,度量数据可以提供决策支持。项目管理和决策制定者可以根据度量数据做出明智的决策。例如,他们可以根据度量数据决定是否进行技术债务的偿还、是否进行性能优化、是否进行安全漏洞修复等关键决策。持续改进是度量驱动开发的核心原则之一。通过分析度量数据,团队可以识别问题的根本原因,并采取措施来不断改进开发流程、工具和实践,以提高效率和质量。最后,度量数据还有助于提高透明度和沟通。团队成员可以共享度量数据,让每个人都了解项目的状态和质量,有助于更好地协作解决问题。

通用化建设

下一个阶段重点建设的方向是监控工具的通用化建设,通用化的工具建设将更加灵活,允许团队根据其特定需求进行定制和扩展,能够满足不同团队和业务的需求。通用化的工具建设将更易于扩展,支持集成新的数据源、第三方插件和自定义脚本,以适应不断变化的技术栈和复杂性。这将为团队提供更大的灵活性,使他们能够构建适合其独特需求的度量驱动开发的解决方案,从而更好地理解和管理他们的技术系统和业务。

智能化建设

人工智能在软件领域有广泛的应用场景,比如AIOps等,未来支持度量驱动开发的工具系统需要更加自动化和智能化。机器学习和人工智能技术将用于分析监测数据,自动检测问题、异常和趋势,并提供实时的反馈和建议。通过机器学习和人工智能技术的应用将更有助于更精准的定位问题,更快地响应和解决问题,减少人为干预的需求,提高效率、可用性和安全性,降低成本,推动团队更好地进行资源利用。

写在最后

正如现代管理学大师彼得·德鲁克所说的“如果你无法度量它,就无法改进它”,度量帮助我们更深刻认识软件工程领域中的方方面面,设定改进方向,并衡量改进效果。

参考文档

Metrics-Driven Development https://legacy.devopsdays.org/events/2012-italy/proposals/MetricsDrivenDevelopment/
An Intro to Metrics Driven Development: What Are Metrics and Why Should You Use Them? https://www.freecodecamp.org/news/metrics-driven-development/
Metrics-Driven Development https://sookocheff.com/post/mdd/mdd/
Metrics-Driven Development https://www.infoq.com/articles/metrics-driven-development/

北京地区摩托车驾照学习考试流程分享

Published / by 高成 / Leave a Comment

挨过一个漫长的冬季过完春节,天气逐渐好转,早高峰的路上依旧蜗行牛步,这时候看着在车流中自由穿梭的摩托车羡慕不已,一时兴起觉得自己需要一个合法的摩托车驾驶手续,本人持有C1驾照,但是C1驾照的准驾车型里并不包含摩托车,如果骑摩托车被警察叔叔查获会被按照无照驾驶处理所持有的C1驾照也会被吊销得不偿失,于是开始考虑考取摩托车驾照了,由于持有驾照需要的是增驾(D或是E、F),D驾照是普通三轮摩托车;E驾照普通二轮摩托车;F驾照是轻便摩托车,D驾照的准驾车型可以覆盖E和F,E驾照的准驾车型可以覆盖F,建议大家直接学习D驾照,准驾车型更加丰富而且考试通过率更高,接下去就是开始了增驾摩托车驾照的过程,与大家做个分享供大家参考。

选择驾校

北京能够学习摩托车驾照的驾校很多,比如海淀驾校、东方时尚、北方驾校、老山驾校、公交驾校等,不同的驾校在费用上面会有一定的差异具体查看各家的官网即可,比如海淀驾校整体的价格就比北方驾校贵300元左右,选择一家适合自己且参加考试学习方便的即可,由于我是在海淀驾校学习的驾照下面的描述都是以海淀驾校为例子,相信其他驾校学习考试的过程也都是大同小异。

材料准备

选择好的驾校之后就要准备报名材料了,近期1寸照片8张(蓝底或是白底),报名需要交6张,2张通过考试后办理驾照会用到,身份证原件、居住证原件(非北京户口,部分驾校可以提供代办服务)、驾照(增驾适用,如果原驾照还在实习期内不可以增加)、报名费用、体检费用,备好这些材料就可以找个驾校的报名点或是预约驾校工作人员上门办理报名即可。

学习考试

摩托车驾照的考试跟汽车类似同样要参加4个科目的考试,分为科目一法规考试(50道题100分)、科目二场地考试(单边桥、坡起、绕桩等)、科目三路考、科目四安全文明驾驶知识考试(50道题100分),了解了需要进行哪些考试剩下的就是参加驾校针对考试进行的训练了。

科目一的考试需要参加一个法规培训,在报名完成之后的第一个周六会组织学员参加法规培训考试,摩托车驾照的法规培训没有刷卡因为驾校就没法过卡,但是法培老师会进行多次点名,点名的时候都在的同学可以参加下周二下午组织的科目一考试,满分100分在题库内共选取50道题每题2分,90分以上包含90分算通过考试,关于学习手机安装一个驾考宝典做2-3遍题,之后再看看错题满分通过考试并不是难事。

科目二、三的训练学习会占用大家一点时间,当然如果您是摩托车方面的高手那另当别论,本人之前并不会骑摩托车所以参加了2天的训练学习,由于学习的D驾照,训练和考试车型均为挎斗摩托(如图,嘉陵600边三轮摩托),E驾照的训练和考试车型为二轮摩托(豪爵125),三轮摩托和两轮摩托的科目二、三的考试也是从日常训练的摩托中选择几辆作为考试用车,科目二、三会一起进行考试以及日常的训练也是一起进行。科目二、三的训练教练会直接让学员骑车,教练坐在挎斗里面给进行一圈的讲解注意事项,三轮摩托和两轮摩托的差异是二轮摩托考试和训练需要佩戴头盔参加,且两轮摩托在参加考试的时候除非考试科目必要考试过程中是不能脚挨地面,三轮摩托车有一次车熄火的机会点火继续考试即可,二轮摩托如果熄火除非脚不挨地可以点火继续考试也可以哈,科目二、三的训练同样也不需要刷卡,教练会有个签到的册子参加训练的同学到了之后去签字即可,一个学期的学员会安排从周一下午考试到周日的训练时间,学员可以自行选择时间参加训练,考试的会安排到下周的周一上午进行,考试前确保签到册上面满足训练次数要求即可。考试以及训练的其他注意事项谨遵教练嘱咐即可。科目二、三的考试会安排学员们排队依次参加考试,考试未通过当场会安排再次进行考试,如果还未通过需要学员在单独约下一次考试,三轮摩托学员考试通过率远高于二轮摩托学员,以本人参加的那次考试为例,三轮摩托学员全部通过考试,二轮摩托学员部分同学只能再次电话约考。科目二、三考试通过之后拿着身份证直接去驾校指定的地点约当天下午的科目四考试。嘉陵600

科目四考试,和科目一考试类似,在科目二、三的训练过程中会安排进行一次科目四的培训同学不需要刷卡法培老师会进行点名点名时候再的同学法培老师会帮助其登记记录,只有参加了法规培训的学员才可以参加科目四的考试。科目四题库相较科目一题库数量少了一些,学习方式还是类似。

持照骑车

通过了科目一到科目四的考试当天会获得摩托车驾照,再加上合法手续的摩托车就算是合法骑车了。本人从报名到拿到驾照共用了23天,3月11日报名,4月2日拿到驾照,整体学习考试过程还是非常顺利的,拿到摩托车驾照以后骑车再也不怕被警察叔叔检查了,不过朋友们还是要注意安全,法培老师说的好什么叫安全?无危为安,无损为全。大家路上切记带好护具安全驾驶。

关于系统重构的10点经验总结

Published / by 高成 / Leave a Comment

做我们的日常工作中系统重构都应该是最让人头疼的工作了,无论是错综复杂还是经意简单的系统在发展的过程中都会经历重构,而系统重构也是任何一个技术团队都无法回避的问题,在我服务的多家公司几乎每家公司都经历了一次甚至多次系统的重构,本文就我在多年的重构工作中总结出来的几点建议分享给各位朋友,希望能够给朋友们带来帮助。

1、重构确定并且聚焦目标

首先我相信我们大家都确信系统重构是会有巨大的成本投入的,业务可能需要暂缓、新系统引入的问题(BUG)带来业务的不稳定、研发人员以及配合人员的投入还有各种隐性成本等等,我们服务的是一家商业公司获取利润是最终目的,在投入具体成本做一个项目就肯定要获得收益的。重构的目标一定要能够获得更大的提升无论是业务流程还是系统性能或是其他方面,如果仅仅一个很小的改善完全没有如此的大费周章,权衡好成本是否能够获得良好的收益。

无论如何进行系统重构都是一次伤筋动骨的过程,是涅槃重生还是飞蛾扑火,完全取决我们项目执行的过程中是否明确了目标且一直聚焦于目标的实现,保持目标的聚集是能否取得良好结果的必要促销,如果我们仅仅确立了目标没有聚集于目标在多个非重要的节点投入较大资源必然会导致我们对目标的投入降低,工作中的原始资本投入都是8个小时,当然如果每个人都愿意乐于加班的话另外讨论,而我们的实际情况往往是8个小时都是不够用的,这就更加需要我们明确目标聚焦目标,把有限的资源投入到最重要的事情中,才能获得既定目标的良好结果。

2、重构要有可量化的指标

团队确认了重构的目标之后,下一步一定要将目标量化,确定好目标之后也就能够确认边界,围绕在边界内要将需要实现的事项一一罗列出来,并且尽可能对每个实现制定可以用数据清晰表现出来的指标,比如用户操作的响应时间缩短到100毫秒、单元测试的覆盖率达到80%、发现问题时长降低到30分钟以内等等,有了明确的数据指标我们才能评估最终是否获得了良好收益,这些目标必须要在重构团队,包括产品、研发、测试等等,甚至包括业务方在内达成一致,是团队的目标清晰明了,防止出现过度或是不达标是最终不能获得良好收益。

3、重构要有更好的质量

既然决定了要对系统进行一次重构,那么我们肯定要做到的就是要比之前做的更好,如果之前接口响应时间在100毫秒,而经过重构之后反而减低到了200毫秒以上那么岂不是很难看,大家辛苦付出的努力是不是也更加不值得。而进行重构往往是一件十分引人注目的事情,一个微小的问题反而容易在众人注目下变得非常严重的问题。为了减少引起不必要的麻烦,重构团队就更加要注重各个方面的问题,无论是系统性能、用户体验还是BUG数量等

4、重构之前要和业务方沟通

技术团队进行系统重构的工作的时候往往忽略掉了业务方,认为这是技术团队内部的事情,不需要知会业务方,这个想法是非常错误的,进行重构的目标就是为了改善改进业务流程,而不去和业务方提前沟通进行闭门造车,最后的结果很可能和进行重构的初衷背道而驰。进行系统重构首先我们必须了解现有系统的业务需求,是否有待改进的业务需求点,是否有新的业务诉求等这些需求往往会影响到我们重构的进度和目标,甚至出现南辕北撤的事情。
技术团队和业务方往往对待问题的出发角度不同,思考问题的方式也不同,在进行重构之前和业务方沟通获得业务方的支持,往往能够事半功倍。
例如,我的团队在进行一块业务系统重构的时候进入到了系统切换的试运行的阶段,由于拿出的方案给到业务方无法被业务方接受,业务方提出的解决方案我们还需要进行再次开放对整个项目进度影响了足足一个月时间之多。吸取教训的我们在进行下一个项目的时候提前和业务方进行了沟通,业务方从他们的角度给予了很多的意见和建议以及业务未来的发展方向的指引,我们发现这些建议和意见帮助我们更好理解业务的同时也大大的降低了我们工作量,减少了我们很多冗余的设计。

5、重构应该才用迭代的方式

参与过重构项目的朋友都知道,重构项目往往是个时间跨度很长的工作,少则一两个月多则一年半载都有,如果不将整个重构进行合理拆分,而是采用全部开发完成,再进行系统切换的方式会对整个重构引入很大的风险,首先长时间的时间跨度内业务会进行持续变更,其次团队面临长时间没有结果输出面临来自各个方面的压力还有系统问题持续累积,这种蒙头狂奔的方式往往造成了项目失败或是目标便宜,而采用迭代方式进行重构,可以以更小的颗粒度持续交付工作成果,交付-试用-反馈-调整,持续有交付,持续有反馈,持续调整能够保证团队的目标不会偏移,形成一个正向循环,保证最后的重构目标。

6、重构要清晰了解旧系统

知己知彼,百战不殆,系统重构是一个与旧系统对抗的过程,不对旧系统的弄的清清楚楚怎么能够比旧系统做的更好呢?其实了解现有系统是一个学习的过程,如果有旧系统的开发人员还在公司那么就事半功倍了,旧系统的开发同学帮忙给做次分享省去了我们重构团队很多的工作,比直接去读代码更能清晰明了的了解到旧系统的相关知识以及有哪些需求点和应该注意的问题等等,通过学习和了解旧系统设定目标基准值避免引入老旧问题也是避免重蹈覆辙的一个好办法。

7、重构要提前规划系统切换方案

不知道朋友有没有遇到过重构完系统发现如果进行新旧系统的切换是个难题,反正我是遇到过,由于没有提前做好规划和切换步骤导致最后临时抱佛脚,开始使用各种奇葩办法做系统切换,有的还需要增加额外工作量甚至各种办法的刷脸求人,总之这不是一个很好的体验。系统切换往往是在重构中被我们忽略的一个步骤,但是这是非常重要的一个环节,在做最初的计划就应该考虑到如何进行系统切换,一个设计好的切换方案也应该贯穿重构始终,避免因为切换方案引起服务不可用或是引入系统BUG。尤其是前期整个团队付出巨大努力取得了一定成果的时候在最后一步切换的时候出现问题对团队是个非常大的打击,也使得业务方对团队失去信心,带来很不必要的麻烦。

8、重构高度重视系统数据

一次系统重构大多数情况下会涉及到数据结构的修改,对数据结构进行修改必然引入很大的风险,尤其在一些老旧的业务系统重构精简业务去掉冗余数据的时候,往往需要将老数据的业务数据重新写入到新系统的数据库。重构的目标是为了比旧系统更好无论是性能还是业务方面,如果我们对数据的操作导致外部依赖旧系统的业务无法正常运行那将是影响SLA指标的问题还有,说到系统数据有些同学可能仅仅关注的是业务数据其实数据也包含了系统运行所产生的日志数据,无论新旧系统的日志数据都是很重要的,如果因为重构影响到数据的读取、处理、分析那么岂不是得不偿失的事情。

9、重构要才用成熟的技术选型

技术选型是重构工作的基石,选择一套成熟稳定的技术方案是重构项目完成的必要条件。有些时候我们引入最新版的数据库虽说会有性能提升但是也会引入一定的不稳定因素,之前我们团队在使用MongoDB的一个新版本的时候发现主从库的数据并不能很好的同步出现过丢失数据的情况,进入社区发现这个版本使用的用户很多都反馈了这个问题,这时候我们不得不选择了大多数人共同的一个选择降低了一个版本来解决问题,相信此类情况比比皆是。在不是很成熟的方案带来并不显著的性能提升反而还会引入不确定的风险的时候我们需要权衡利弊得失,重构更是要保证系统的稳定性。
技术方案能否有足够强大的支撑也是我们需要考虑的一个方面,现在我们团队面对的重构是从单体式架构往微服务转变,旧系统的版本构建在是PHP语言上,新的系统我们由两个选择继续选择用PHP进行重构或是才用公司统一的微服务框架,我们毫不犹豫的选择了使用公司统一的微服务,这样做有几个显而易见的好处。
1、和公司内部进行交互更加方便快捷;
2、可以直接获取成熟的经验;
3、基础服务有公司级的支持;
以上的好处显然对我们能否成功重构系统并且获得足够的帮助起到了显著的帮助,反而才用PHP进行微服务,公司内部并无成功经验可以借鉴,业内也并无太多可靠的方案可以进行选择。一个成熟可靠的的技术方案是我们能否更进一步的保障和基石。

10、重构更加关注重视团队成员

参与过重构的同学都知道重构工作是一项枯燥乏味的工作,往往周期长、复杂度、 难度大、牵扯广、优先级低而且很有可能是一件费力不讨好的工作,开发一个业 务方期待的新功能、新模块往往比一场翻天覆地的重构更能引起业务方的重视也 更容易获取良好结果与反馈,反而不需要承担大多的压力。而越是面对这样的情 况越是需要加大对团队的鼓励增强团队的信心,消除团队的疑虑困惑,给予团队 持续的鼓励,给整个团队注入正能量,让团队保持积极向上的团队氛围,即使面 对各种困难、问题,也始终对团队保持信心保持乐观,让大家轻松愉快的投入到 重构工作中,尽量不担负额外的压力。

以内内容均为工作中的总结反思,分享给大家希望以上的这些总结能够对大家有所帮助,文章所讲述的内容如有不足之处还望指出。

log4php日志框架的配置使用介绍

Published / by 高成 / Leave a Comment

随着系统和业务的复杂度提升我们会对日志进行各种分类处理如通过日志的级别分类或是对不同的业务的日志进行分类处理,即使面对以上的需要我们仍然需要有一个统一的日志格式,这样就需要我们有一个标准的日志模块来完成这些工作,然而我们也希望这个日志模块是性能优良且方便易用的。

Java有一个比较出名的日志组件log4j,PHP语言也有类似的日志框架,同样来自于Apache的log4php是一个多功能的为PHP使用的日志框架。和log4j类似,通过log4php我们也可以控制日志信息输送的目的地是控制台、文件、数据库甚至是套接口服务器、syslog守护进程等,同样我们也可以控制每一条日志的输出格式;通过定义日志信息的级别,我们能够更加有效细致地控制日志的生成过程。更加惊喜的是以上叙述的这些功能甚至不需要我们修改代码,而是通过一个配置文件来灵活地进行配置。

安装介绍

log4php提供了两种安装方式,一是通过直接下载源码包,Apache log4php - Download;二是通过PEAR渠道安装。

PEAR方式安装命令

pear channel-discover pear.apache.org/log4php
pear install log4php/Apache_log4php

目录结构

├───apidocs - API生成文档
└───src

├───assembly - Maven的配置
├───changes - 更新日志
├───examples - 各种用法示例
├───main
│       └───php - 主要源码
├───site - 网站源码
└───test - 单元测试

配置介绍

log4php支持XML、PHP以及Properties三种配置文件,我们今天主要通过Properties方式的配置文件来讲解,此种方式的配置较为全面。如果不在日志记录前调用Logger::configure()方法进行配置,log4php使用默认方式进行配置

日志输出方式

名称                                     介绍
LoggerAppenderConsole         控制台,标准输出或标准错误流。
LoggerAppenderEcho             控制台,通过PHP的echo方式输出
LoggerAppenderFile               文件
LoggerAppenderDailyFile        文件(通过日志生成新文件)
LoggerAppenderRollingFile     文件 (通过尺寸设置生成新的日志文件).
LoggerAppenderMail              通过电子邮件发送日志,整个日志在一个电子邮件发送。
LoggerAppenderMailEvent      通过电子邮件发送日志,每条日志通过单独的电子邮件发送。
LoggerAppenderMongoDB      MongoDB
LoggerAppenderNull              忽略所有的日志事件
LoggerAppenderPDO             数据库
LoggerAppenderPhp              通过使用PHP trigger_error()函数PHP用户级的消息
LoggerAppenderSocket          通过套接口输出日志
LoggerAppenderSyslog          syslog

日志内容输出格式方式

名称                                   介绍
LoggerLayoutHTML              输出到HTML表格中
LoggerLayoutPattern            灵活格式,通过一个字符串配置
LoggerLayoutSimple             简单格式,不可配置
LoggerLayoutSerialized         输出序列化对象
LoggerLayoutTTCC               包括时间,主题,类别和嵌套诊断上下文的 (不建议使用)
LoggerLayoutXml                 输出到XML文件

示例说明

示例一

配置示例

;定义输出方式名称default
log4php.appender.default = LoggerAppenderEcho
log4php.appender.default.layout = LoggerLayoutSimple

;定义一组新的输出方式名称为test
;日志输出方式设置
log4php.appender.test = LoggerAppenderDailyFile
;日志内容格式设置
log4php.appender.test.layout = LoggerLayoutPattern
;日志内容参数设置(日期 PID 日志级别 日志名称 日志文本 换行符)
log4php.appender.test.layout.ConversionPattern = "%d{Y-m-d H:i:s.u} [%t] %p %c: %m%n"
;日志文件名称配置
log4php.appender.test.datePattern = Ymd
;日志文件路径配置
log4php.appender.test.file = /var/log/daily_%s.log

;日志输出方式以及输入级别设置
log4php.rootLogger = DEBUG, default

如果设置为已下值,日志可同时使用default和test两个输出定义进行记录
log4php.rootLogger = DEBUG, default,test

代码示例

<?php

require_once dirname(__FILE__) . '/log4php/main/php/Logger.php';
Logger::configure(dirname(__FILE__) . '/log4php.properties');
$logger = Logger::getLogger('exception');
$message = 'hello world!';
$logger->error('error,' . $message);//会产生记录
$logger->info('info,' . $message);//会产生记录
$logger->trace('trace,' . $message);//不会产生记录,因为设置的日志级别DEBUG,只有高于等于DEBUG级别的日志才会记录

输出示例

2016-12-15 16:25:55.55 [121215] ERROR exception: error,hello world!
2016-12-15 16:25:55.55 [121215] INFO exception: info,hello world!

示例二

配置示例

;定义输出方式名称default
log4php.appender.default = LoggerAppenderEcho
log4php.appender.default.layout = LoggerLayoutSimple

;定义一组新的输出方式名称为test
;日志输出方式设置
log4php.appender.test = LoggerAppenderDailyFile
;日志内容格式设置
log4php.appender.test.layout = LoggerLayoutPattern
;日志内容参数设置(日期 PID 日志级别 日志名称 日志文本 换行符)
log4php.appender.test.layout.ConversionPattern = "%d{Y-m-d H:i:s.u} [%t] %p %c: %m%n"
;日志文件名称配置
log4php.appender.test.datePattern = Ymd
;日志文件路径配置
log4php.appender.test.file = /var/log/test_daily_%s.log
;日志输出方式以及输入级别设置
log4php.logger.test = INFO, test

;定义一组新的输出方式名称为pro
;日志输出方式设置
log4php.appender.pro = LoggerAppenderDailyFile
;日志内容格式设置
log4php.appender.pro.layout = LoggerLayoutPattern
;日志文内容式参数配(日期 PID 日志级别 日志名称 日志文本 换行符)
log4php.appender.test.layout.ConversionPattern = "%d{Y-m-d H:i:s.u} [%t] %p %c: %m%n"
;日志文件名称配置
log4php.appender.pro.datePattern = Ymd
;日志文件路径配置
log4php.appender.pro.file = /var/log/pro_daily_%s.log
;日志输出方式以及输入级别设置
log4php.logger.pro = INFO, pro

代码示例

<?php
require_once dirname(__FILE__) . '/log4php/main/php/Logger.php';
Logger::configure(dirname(__FILE__) . '/log4php.properties');

/*
* 使用名称为test的方式处理日志
*/
$logger = Logger::getLogger('test');
$message = 'hello world!';
$logger->error($message);//会产生记录

/*
* 使用名称为pro的方式处理日志
*/
$logger = Logger::getLogger('pro');
$message = 'Hey, beautiful!';
$logger->error($message);//会产生记录

输出示例

/var/log/test_daily_20161215.log文件

2016-12-15 16:25:55.55 [121215] ERROR test: hello world!

/var/log/pro_daily_20161215.log文件

2016-12-15 16:25:55.55 [121215] ERROR test: Hey, beautiful!

log4php的配置文件十分灵活和简单,以上的只是很简单的两个示例,还不能全面的展示出来log4php配置方面的简单易用以及灵活性,仍然希望这能够对大家有所帮助,log4php的官方提供了良好的文档以及十分丰富的API,几乎满足了我们对于日志模块需要的全部需求,大家也可以通过查阅相关文档调整配置做出自己需要的日志模块。

log4php文档地址:http://logging.apache.org/log4php/index.html

希望这篇文章对你有所帮助,如果没有任何帮助抱歉浪费了你的阅读时间但是我不负任何责任,如有不足支持还望指出

给开发工程师关于日志记录的建议

Published / by 高成 / Leave a Comment

摘要

对于工程师而言懂得记录合理正确的日志是件很艰巨的任务。日志是记录必要的信 息和数据,方便问题定位和追踪,给我们足够的依据解释和发现问题,以及帮我们清晰 反映出应用的运行状况,这或许能够决定一个工程师是升职还是被开除。记录日志也是 有一定原则或是技巧的,并不是把所有内容有加以记录就可以了,一是可能收到运维工 程师的抗议;二是记录过多内容反而不容易查找关键信息,说来我们的日志记录的简单 可依赖即可,简单可以依赖的关键性数据。

一.日志要分级

日志一定要分级。多个级别的日志等级TRACE、DEBUG、INFO、NOTICE、 WARNING、ERROR、FATAL等,不同级别的日志应当分类处理,在大型应用的海量 日志面前不分级的日志处理起来非常麻烦,我们必须要对日志进行分级分类处理,清楚的明白哪些级别的日志需要时刻关注,影响到了应用的正常运行,有些日志只是帮我们在记录应用的运行状态。

二.日志记录必要的信息即可

日志记录必要的信息即可,无意义的信息必须要排除在日志之外,开发工程师作为对程序最了解的人如果在记录含糊不清的日志只会增加我们查询关键信息的困难,且过多的内容记录也会招致运维工程师的反感和增加应用运行的成本,我们要明白当应用出现问题的时候日志是你唯一可以依赖的,请让保存记录最关键的信息。

三.日志要让其他人也能看懂

为什么要记录日志,是因为有一天我们要去读他,而读他日志的不一定是谁,有一定加密属性的日志读起来总会给我们带来很大困惑,请善待日志的读者,因为每个人都会是日志的读者。
1.排版整洁有序,格式统一规范。随笔式的日志看起来会很麻烦,给日志读者增加很多困难。
2.采用关键字来突出显示如:时间、操作名称等,让读者能够轻松通过关键字来精确定位日志内容。

四.关于程序中加入日志的方法

千万不要自己写个记录日志的方法!千万不要自己写个记录日志的方法!千万不要自己写个记录日志的方法!重要的事情说三遍,绝对不要这么做,即便是用打印输入或者是自己 写入到日志文件中,第一个这么做的朋友也会影响其他同事——首先,这会让你的代码不那么美;其次也会给你的运维工程师带来很大麻烦。每个人都自己写个日志会很容易造成日志 个格式不统一,这会给日志的收集分类带来很大麻烦,PHP有不少第三方的log类库弥补了上述缺陷,如log4php、plog、Analog等还有内置error_log、syslog函数功能强大且性能 极好,用Java开发也有很多选择,例如Log4j、SLF4J、和Logback等其他语言如Python、ruby也有相应的日志类库或是组件,请调用标准类库来完成日志记录。

五.日志要做到方便解析

日志记录下来一定要做到可以方便解析,因为有些时候需要做到报警或是数据提取,这 些功能往往是需要自动化实现的,如果没有一个方便解析的日志实现起来就增加了很多成本。如下,日志记录了时间、日志级别、脚本、IP地址,以及数据:
2015-12-15 12:00:00ERRORlist.php127.0.0.1PAGE=1&NUM=500 解析以上日志是不是需要正则表达式或是更麻烦的程序逻辑来处理?答案是肯定的,如果换一种方式,很可能需要很少的工作就能达到我想要的效果。如下:
2015-12-15 12:00:00||ERROR||list.php||127.0.0.1||{'PAGE':1,'NUM':500} 这样解析起来awk -F‘||’就可以轻松解决了。

总结

希望这篇文章对您在开发过程中记录日志有所帮助,如果有什么遗漏之处还望见谅。看了这篇文章之后发掘没有任何帮助,抱歉我概不负责。

最苦与最乐

Published / by 高成 / Leave a Comment

  梁启超

  一九二二年八月十二日《时事新报·学灯》

  人生什么事最苦呢?贫吗?不是。失意吗?不是。老吗?死吗?都不是。我说人生最苦的事,莫苦于身上背著一种未了的责任。人若能知足,虽贫不苦;若能安分(不多作分外希望),虽然失意不苦;老、死乃人生难免的事,达观的人看得很平常,也不算什么苦。独是凡人生在世间一天,便有一天应该的事。该做的事没有做完,便像是有几千斤重担子压在肩头,再苦是没有的了。为什么呢?因为受那良心责备不过,要逃躲也没处逃躲呀!

答应人办一件事没有办,欠了人的钱没有还,受了人的恩惠没有报答,得罪了人没有赔礼,这就连这个人的面也几乎不敢见他;纵然不见他的面,睡里梦里,都像有他的影子来缠着我。为什么呢?因为觉得对不住他呀!因为自己对他的责任,还没有解除呀!不独是对于一个人如此,就是对于家庭、对于社会、对于国家,乃至对于自己,都是如此。凡属我受过他好处的人,我对于他便有了责任。凡属我应该做的事,而且力量能够做得到的,我对于这件事便有了责任。凡属我自己打主意要做一件事,便是现在的自己和将来的自己立了一种契约,便是自己对于自己加一层责任。有了这责任,那良心便时时刻刻监督在后头,一日应尽的责任没有尽,到夜里头便是过的苦痛日子;一生应尽的责任没有尽,便死也带著苦痛往坟墓里去。这种苦痛却比不得普通的贫困老死,可以达观排解得来。所以我说人生没有苦痛便罢,若有苦痛,当然没有比这个加重的了。

翻过来看,什么事最快乐呢?自然责任完了,算是人生第一件乐事。古语说得好:“如释重负”;俗语亦说是:“心上一块石头落了地”。人到这个时候,那种轻松愉快,直是不可以言语形容。责任越重大,负责的日子越久长,到责任完了时,海阔天空,心安理得,那快乐还要加几倍哩!大抵天下事从苦中得来的乐才算真乐。人生须知道有负责任的苦处,才能知道有尽责任的乐处。这种苦乐循环,便是这有活力的人间一种趣味。却是不尽责任,受良心责备,这些苦都是自己找来的。一翻过去,处处尽责任,便处处快乐;时时尽责任,便时时快乐。快乐之权,操之在己。孔子所以说:“无入而不自得”,正是这种作用。

然则为什么孟子又说:“君子有终身之忧”呢?因为越是圣贤豪杰,他负的责任越是重大;而且他常要把这种种责任来揽在身上,肩头的担子从没有放下的时节。曾子还说哩:“任重而道远”,“死而后已,不亦远乎?”那仁人志士的忧民忧国,那诸圣诸佛的悲天悯人,虽说他是一辈子感受苦痛,也都可以。但是他日日在那里尽责任,便日日在那里得苦中真乐,所以他到底还是乐,不是苦呀!

有人说:“既然这苦是从负责任而生的,我若是将责任卸却,岂不是就永远没有苦了吗?”这却不然,责任是要解除了才没有,并不是卸了就没有。人生若能永远像两三岁小孩,本来没有责任,那就本来没有苦。到了长成,责任自然压在你的肩头上,如何能躲?不过有大小的分别罢了。尽得大的责任,就得大快乐;尽得小的责任,就得小快乐。你若是要躲,倒是自投苦海,永远不能解除了。

python import this python 哲学

Published / by 高成 / Leave a Comment


Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
>>>

Beautiful is better than ugly.
优美胜于丑陋。
Explicit is better than implicit.
明了胜于晦涩。
Simple is better than complex.
简单胜过复杂。
Complex is better than complicated.
复杂胜过凌乱。
Flat is better than nested.
扁平胜于嵌套。
Sparse is better than dense.
间隔胜于紧凑。
Readability counts.
可读性很重要。
Special cases aren't special enough to break the rules.
即便假借特例的实用性之名,也不可违背这些规则。
Although practicality beats purity.
虽然实用性次纯度。
Errors should never pass silently.
错误不应被无声的忽略。
Unless explicitly silenced.
除非明确地沉默。
In the face of ambiguity, refuse the temptation to guess.
当存在多种可能,不要尝试去猜测。
There should be one-- and preferably only one --obvious way to do it.
应该有一个 - 最好只有一个 - 明显的能做到这一点。
Although that way may not be obvious at first unless you're Dutch.
虽然这种方式可能不容易,除非你是 Python 之父。
Now is better than never.
现在做比不做好。
Although never is often better than *right* now.
虽然过去从未比现在好。
If the implementation is hard to explain, it's a bad idea.
如果这个实现不容易解释,那么它是个坏主意。
If the implementation is easy to explain, it may be a good idea.
如果这个实现容易解释,那么它或许是个好主意。
Namespaces are one honking great idea -- let's do more of those!
命名空间是一种绝妙的理念,我们应当多加利用。

Ubuntu下安装GoAccess过程中对源代码编译时产生错误的处理方法

Published / by 高成 / Leave a Comment

前几日在VPS上面重新安装了下GoAccess,以前博主为图省事直接用的apt-get install goaccess进行的安装,没有对源代码进行编译安装,在Ubuntu下编译的时候不能通过报出了两个错误,博主于是发邮件给GoAccess官方需求解决方法,很快得到的回复。对了GoAccess官方邮件地址是goaccess(at)prosoftcorp.com,有问题可以直接给他们发邮件,很快就会得到答复!
我安装的时候产生的错误是这样的

gcc -g -Wall -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include   -lmenuw -lncursesw -lm  -o goaccess settings.o error.o commons.o goaccess.o parser.o ui.o util.o  -lglib-2.0 -lmenuw -lncursesw 
ui.o: In function `create_graphs':
/usr/local/goaccess/ui.c:300: undefined reference to `log10'
/usr/local/goaccess/ui.c:300: undefined reference to `floor'
ui.o: In function `data_by_total_hits':
/usr/local/goaccess/ui.c:390: undefined reference to `log10'
/usr/local/goaccess/ui.c:390: undefined reference to `floor'
collect2: ld returned 1 exit status
make[1]: *** [goaccess] Error 1
make[1]: Leaving directory `/usr/local/goaccess'
make: *** [all] Error 2

官方的给出的解决办法是
首先安装autoconf,如果没有安装的话

apt-get install autoconf

打开Makefile.am文件查看是否有如下两行的内容,没有则进行添加

AM_CFLAGS = -g -Wall @GLIB2_CFLAGS@
goaccess_LDADD = -lm

修改configure.ac文件

vi configure.ac

注释掉AM_INIT_AUTOMAKE,然后执行以下命令

autoheader
autoconf

再次修改configure.ac文件

vi configure.ac

将AM_INIT_AUTOMAKE注释去掉,然后执行以下命令

aclocal
automake -a
autoconf

再次进行编译顺利通过,GoAccess官方建议用git获取源代码

git clone git://goaccess.git.sourceforge.net/gitroot/goaccess/goaccess

我也是通过这种方式获取的源代码进行修改之后编译安装顺利通过

简述uWSGI+Nginx+Python 搭建过程

Published / by 高成 / 简述uWSGI+Nginx+Python 搭建过程有1条评论

由于服务器上面的Python和Nginx都已经安装完毕,咱们就直接叙述uWSGI的安装,对照各方面的测试数据uWsgi在性能方面相对其他方式还是比较不错的!他是一个快速的、纯C语言开发的、自维护的、对开发者或是系统管理员友好的应用程序服务器。

官方网址:http://projects.unbit.it/uwsgi/

文档地址:http://projects.unbit.it/uwsgi/wiki/Doc

准备

cd /usr/local
wget http://projects.unbit.it/downloads/uwsgi-1.0.2.1.tar.gz

安装

tar zxvf uwsgi-1.0.2.1.tar.gz
cd uwsgi-1.0.2.1/
python uwsgiconfig.py --build

配置

cp nginx/uwsgi_params /usr/local/nginx/conf/
vi /usr/local/nginx/conf/nginx.conf

编辑Nginx配置文件添加,uWSGI监听8000端口,这个原理跟PHP的fastcgi相同

    server {
        listen        80;
        server_name py.wuwangwo.net;

        location / {
            root  /data/htdocs/py.wuwangwo.net;
            include uwsgi_params;
            uwsgi_pass 127.0.0.1:8000;
        }

        access_log  /data1/logs/py.wuwangwo.net.access.log;
    }

重新启动Nginx

/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf -s reload

配置web站点

cd /data/htdocs/py.wuwangwo.net
vi uwsgi.xml

编辑uWSGI配置文件,他也同样支持.ini文件等的配置形式,个人习惯不同,具体可以参照官方示例:http://projects.unbit.it/uwsgi/wiki/Example


127.0.0.1:8000
myuwsgi

/data/htdocs/py.wuwangwo.net
2

编辑web.py文件

#!/usr/bin/env python

import os
import web

urls = ('/(.*)', 'hello')

app = web.application(urls, globals())

class hello:
    def GET(self, name):
        if not name:
            name = "World"
        return "Hello" + name + "!"

application = app.wsgifunc()

启动uWSGI,添加--daemonize参数以后台方式运行

/usr/local/uwsgi-1.0.2.1/uwsgi -x /data/htdocs/py.bukaopu.org/uwsgi.xml --daemonize /data/htdocs/py.wuwangwo.net/uwsgi.error.log

停止uWSGI

killall -9 uwsgi

MongoDB之no db response数据库没有响应

Published / by 高成 / MongoDB之no db response数据库没有响应有1条评论

今天查看PHP的error log有很多错误产生,有Fatal error也有Warning,本着错误的级别先开始处理Fatal error除了几条还被搜索机器人抓取的不在使用的页面产生这种错误外,发现了一个多行的Fatal error仔细查看下是:

[17-Jan-2012 11:16:19] PHP Fatal error:  Uncaught exception 'MongoCursorException' with message 'no db response' in XXXXX.php:194

乍一看是为捕获抛出的异常,异常的错误信息是'no db response'数据库没有响应,接下去查看代码:

省略...
$query = array('type' => 5);
$cursor = $collection->find($query);
foreach($cursor as $key => $val) {//出错的行
	省略...
}
省略...

变量$cursor为查询MongoDB的返回结果,但是抛出的异常是'MongoCursorException'异常信息是'no db response',查看PHP手册解释是:This may not even be an error, for example, the database command "shutdown" returns no response. However, if you were expecting a response, this means the database didn't give one.坑爹的PHP手册上来就说:This may not even be an error(这甚至有可能不会是一个错误),for example, the database command "shutdown" returns no response.(例如,数据库输入'shutdown'命令而没有获得相应)。
访遍Google、百度没有获得满意的答案,不过问题应该已经比较清晰出现在了MongoDB或是网络上面,于是继续想办法查找问题中,截止到博文发布还没有找到问题原因!