All posts by dotte

去哪儿网基于Mesos和Docker构建私有云服务的实践

作者:徐磊

【导读】本文深入介绍了去哪儿网利用Mesos和Docker构建私有云服务的全过程,分享了从无状态应用向有状态应用逐步过度的经验与心得。

平台概览

2014年下半年左右,去哪儿完成了有关构建私有云服务的技术调研,并最终拍定了Docker/Mesos这一方案。下图1展示了去哪儿数据平台的整体架构:

大数据

图1:去哪儿数据平台的整体架构

该平台目前已实现了如下多项功能:

  • 每天处理约340亿/25TB的数据;
  • 90%的数据在100ms内完成处理;
  • 最长3h/24h的数据回放;
  • 私有的Elasticsearch Cloud;
  • 自动化监控与报警。

为什么选择Docker/Mesos

目前为止,这个数据平台可以说是公司整个流数据的主要出入口,包括私有的Elasticsearch Cloud和监控报警之类的数据。那么为什么选择Docker/Mesos?

选择Docker有两大原因。第一个是打包:对于运维来讲,业务打完包之后,每天面对的是用脚本分发到机器上时所出现的各种问题。业务包是一个比较上层的话题,这里不做深入的讨论,这里讲的“打包”指软件的Runtime层。如果用Docker的打包机制,把最容易出现问题的Runtime包装成镜像并放在registry里,需要的时候拿出来,那么整个平台最多只执行一个远程脚本就可以了,这是团队最看好的一个特性。第二个是运维:Docker取消了依赖限制,只要构建一个虚拟环境或一个Runtime的镜像,就可以直接拉取到服务器上并启动相应的程序。此外Docker在清理上也较为简单,不需要考虑环境卸载不干净等问题。

以常见的计算框架来说,它们本质上仍然属于运行在其上的Job的Runtime。综合上述情况,团队选择针对Runtime去打包。

选择Mesos是因为它足够简单和稳定,而且拥有较成熟的调度框架。Mesos的简单体现在,与Kubernetes相比其所有功能都处于劣势,甚至会发现它本身都是不支持服务的,用户需要进行二次开发来满足实际要求,包括网络层。不过,这也恰好是它的强项。Mesos本身提供了很多SDN接口,或者是有模块加载机制,可以做自定义修改,平台定制功能比较强。所以用Mesos的方案,需要考虑团队是否可以Hold住整个开发过程。

从框架层面来看,Marathon可以支撑一部分长期运行的服务,Chronos则侧重于定时任务/批处理。

以下图2是Mesos的一个简单结构图:

大数据

图2:Mesos结构

数据平台的最终目标架构如下图3所示:

大数据

图3:平台目标

组件容器化与部署

组件的容器化分为JVM容器化和Mesos容器化。JVM容器化需要注意以下几方面:

潜在创建文件的配置都要注意

  • java.io.tmpdir
  • -XX:HeapDumpPath
  • -Xloggc

-Xloggc会记录GC的信息到制定的文件中。现在很少有直接用XLoggc配置的了(已经用MXBean方式替代了)。如果有比较老的程序是通过-Xloggc打印GC日志的话,那么要额外挂载volume到容器内。

时区与编码

  • –env TZ=Asia/Shanghai
  • –volume /etc/localtime:/etc/localtime:ro
  • –env JAVA_TOOL_OPTIONS=”-Dfile.encoding=UTF-8 -Duser.timezone=PRC

时区是另一个注意点。上面所列的三种不同的方法都可以达到目的,其中第一/三个可以写在Dockerfile里,也可以在docker run时通过–env传入。第二种只在docker run时通过volume方式挂载。另外,第三种额外设置了字符集编码,推荐使用此方式。

主动设置heap

  • 防止ergonomics乱算内存

这是Docker内部实现的问题。即使给Docker设置内存,容器内通过free命令看到的内存和宿主机的内存是一样的。而JVM为了使用方便,会默认设置一个人机功能会根据当前机器的内存计算一个堆大小,如果我们不主动设置JVM堆内存的话,很有可能计算出一个超过 Memory Cgroup限制的内存,启动就宕掉,所以需要注意在启动时就把内存设置好。

CMS收集器要调整并行度

  • -XX:ParallelGCThreads=cpus
  • -XX:ConcGCThreads=cpus/2

CMS是常见的收集器,它设置并行度的时候是取机器的核数来计算的。如果给容器分配2个CPU,JVM仍然按照宿主机的核数初始化这些线程数量,GC的回收效率会降低。想规避这个问题有两点,第一点是挂载假的Proc文件系统,比如Lxcfs。第二种是使用类似Hyper的基于Hypervisor的容器。

Mesos容器化要求关注两类参数:配置参数和run参数。

  • 需要关注的配置参数
    • MESOS_systemd_enable_support
    • MESOS_docker_mesos_image
    • MESOS_docker_socket
    • GLOG_max_log_size
    • GLOG_stop_logging_if_full_disk

Mesos是配置参数最多的。在物理机上,Mesos默认使用系统的Systemd管理任务,如果把Mesos通过Docker run的方式启动起来,用户就要关systemd_Enable_support,防止Mesos Slave拉取容器运行时数据造成混乱。

第二个是Docker_Mesos_Image,这个配置告诉Mesos Slave,当前是运行在容器内的。在物理机环境下,Mesos Slave进程宕掉重启,、就会根据executor进程/容器的名字做recovery动作。但是在容器内,宕机后executor全部回收了,重启容器,Slave认为是一个新环境,跳过覆盖动作并自动下发任务,所以任务有可能会发重。

Docker_Socket会告诉Mesos,Docker指定的远端地址或本地文件,是默认挂到Mesos容器里的。用户如果直接执行文件,会导致文件错误,消息调取失败。这个时候推荐一个简单的办法:把当前物理机的目录挂到容器中并单独命名,相当于在容器内直接访问整个物理机的路径,再重新指定它的地址,这样每次一有变动Mesos就能够发现,做自己的指令。

后面两个是Mesos Logging配置,调整生成logging文件的一些行为。

  • 需要关注的run参数
    • –pid=host
    • –privileged
    • –net=host (optional)
    • root user

启动Slave容器的时候最好不加Pid Namespace,因为容器内Pid=1的进程一般都是你的应用程序,易导致子进程都无法回收,或者采用tini一类的进程启动应用达到相同的目的。–privileged和root user主要是针对Mesos的持久化卷功能,否则无法mount到容器内,–net=host是出于网络效率的考虑,毕竟源生的bridge模式效率比较低。

大数据

图4:去哪儿数据平台部署流程图

上图4就是去哪儿数据平台部署的流程图。

基于Marathon的Streaming调度

拿Spark on Mesos记录子,即使是基于Spark的Marathon调度,也需要用户开发一个Frameworks。上生产需要很多代码,团队之前代码加到将近一千,用来专门解决Spark运行在Master中的问题,但是其中一个软件经常跑到Master,对每一个框架写重复性代码,而且内部逻辑很难复用,所以团队考虑把上层的东西全都跑在一个统一框架里,例如后面的运维和扩容,都针对这一个框架做就可以了。团队最终选择了Marathon,把Spark作为Marathon的一个任务发下去,让Spark在Marathon里做分发。

除去提供维标准化和自动化外,基于Spark的Marathon还可以解决Mesos-Dispatcher的一些问题:

  • 配置不能正确同步;这一块更新频率特别慢,默认速度也很慢,所以需要自己来维护一个版本。第一个配置不能正确同步,需要设置一些参数信息、Spark内核核数及内损之类,这里它只会选择性地抽取部分配置发下去。
  • 基于attributes的过滤功能缺失;对于现在的环境,所设置的Attributes过滤功能明显缺失,不管机器是否专用或有没有特殊配置,上来就发,很容易占满ES的机器。
  • 按role/principal接入Mesos;针对不同的业务线做资源配比时,无法对应不同的角色去接入Mesos。
  • 不能re-registery;框架本身不能重注册,如果框架跑到一半挂掉了,重启之后之前的任务就直接忽略不管,需要手工Kill掉这个框架。
  • 不能动态扩容executor。最后是不能扩容、动态调整,临时改动的话只能重发任务。

整个过程比较简单,如下图5所示:

大数据

图5:替代Spark Mesos Dispatcher

不过还是有一些问题存在:

Checkpoint & Block

  • 动态预留 & 持久化卷
  • setJars
  • 清理无效的卷

关于Checkpoint&Block,通过动态预留的功能可以把这个任务直接“钉死”在这台机器上,如果它挂的话可以直接在原机器上重启,并挂载volume继续工作。如果不用它预留的话,可能调度到其他机器上,找不到数据Block,造成数据的丢失或者重复处理。

持久化卷是Mesos提供的功能,需要考虑它的数据永存,Mesos提供了一种方案:把本地磁盘升级成一个目录,把这个转移到Docker里。每次写数据到本地时,能直接通过持久化卷来维护,免去手工维护的成本。但它目前有一个问题,如果任务已被回收,它持久化卷的数据是不会自己删掉的,需要写一个脚本定时轮巡并对应删掉。

临时文件

  • java.io.tmpdir=/mnt/mesos/sandbox
  • spark.local.dir=/mnt/mesos/sandbox

如果使用持久化卷,需要修改这两个配置,把这一些临时文件写进去,比如shuffle文件等。如果配置持久化卷的话,用户也可以写持久化卷的路径。

Coarse-Grained

Spark有两种资源调度模式:细粒度和粗粒度。目前已经不太推荐细粒度了,考虑到细粒度会尽可能的把所有资源占满,容易导致Mesos资源被耗尽,所以这个时候更倾向选择粗粒度模式。

大数据

图6:Storm on Marathon

上图6展示了基于Storm的Marathon调度,Flink也是如此。结合线上的运维和debug,需要注意以下几方面:

源生Web Console

  • 随机端口
  • OpenResty配合泛域名
  • 默认源生Web Console,前端配置转发,直接访问固定域名。

Filebeat + Kafka + ELK

  • 多版本追溯
  • 日常排错
  • 异常监控

大部分WebUI上看到的都是目前内部的数据处理情况,可以通过ELK查询信息。如果任务曾经运行在不同版本的Spark上,可以把多版本的日志都追踪起来,包括日常、问题监控等,直接拿来使用。

Metrics

第三个需要注意的就是指标。比如Spark ,需要配合Metrics把数据源打出来就行。

ELK on Mesos

目前平台已有近50个集群,约100TB+业务数据量,高峰期1.2k QPS以及约110个节点,Elasticsearch需求逐步增多。

大数据

图7:ELK on Mesos

上图7是ELK on Mesos结构图,也是团队的无奈之选。因为Mesos还暂时不支持multi-role framework功能,所以选择了这种折中的方式来做。在一个Marathon里,根据业务线设置好Quota后,用业务线重新发一个新的Marathon接入进去。对于多租户来讲,可以利用Kubernetes做后续的资源管控和资源申请。

部署ES以后,有一个关于服务发现的问题,可以去注册一个callback,Marathon会返回信息,解析出master/slave进程所在的机器和端口,配合修改Haproxy做一层转发,相当于把后端整个TCP的连接都做一个通路。ES跟Spark不完全相同,Spark传输本身流量就比较大,而ES启动时需要主动联系Master地址,再通过Master获取相应集群,后面再做P2P,流量比较低,也不是一个长链接。

监控与运维

这部分包括了Streaming监控指标与报警、容器监控指标与报警两方面。

Streaming监控指标与报警

Streaming监控含拓扑监控和业务监控两部分。

  • Streaming拓扑监控
  • 业务监控
    • Kafka Topic Lag
    • 处理延迟mean90/upper90
    • Spark scheduler delay/process delay
    • Search Count/Message Count
    • Reject/Exception
    • JVM

拓扑监控包括数据源和整个拓扑流程,需要用户自己去整理和构建,更新的时候就能够知道这个东西依赖谁、是否依赖线上服务,如果中途停的话会造成机器故障。业务监控的话,第一个就是Topic Lag,Topic Lag每一个波动都是不一样的,用这种方式监控会频繁报警,90%的中位数都是落在80—100毫秒范围内,就可以监控到整个范围。

容器监控指标与报警

容器监控上关注以下三方面:

  • Google cAdvisor足够有效
    • mount rootfs可能导致容器删除失败 #771
    • –docker_only
    • –docker_env_metadata_whitelist
  • Statsd + Watcher
    • 基于Graphite的千万级指标监控平台
  • Nagios

容器这一块比较简单,利用Docker并配合Mesos,再把Marathon的ID抓取出来就可以了。我们这边在实践的过程发现一个问题,因为Statsd Watcher容易出现问题,你直接用Docker的时候它会报一些错误出来,这个问题就是Statsd Watcher把路径给挂了的原因。目前我们平台就曾遇到过一次,社区里面也有人曝,不过复现率比较低。用的时候如果发现这个问题把Statsd Watcher直接停掉就好。指标的话,每台机器上放一个statsd再发一个后台的Worker,报警平台也是这个。

其实针对Docker监控的话,还是存在着一些问题:

  • 基础监控压力
    • 数据膨胀
    • 垃圾指标增多
    • 大量的通配符导致数据库压力较高
  • 单个任务的容器生命周期
    • 发布
    • 扩容
    • 异常退出

首先主要是监控系统压力比较大。原来监控虚拟机时都是针对每一个虚拟机的,只要虚拟机不删的话是长期汇报,指标名固定,但在容器中这个东西一直在变,它在这套体系下用指标并在本地之外建一个目录存文件,所以在这种存储机制下去存容器的指标不合适。主要问题是数据膨胀比较厉害,可能一个容器会起名,起名多次之后,在Graphite那边对应了有十多个指标,像这种都是预生成的监控文件。比如说定义每一秒钟一个数据点,要保存一年,这个时候它就会根据每年有多少秒生成一个RRD文件放那儿。这部分指标如果按照现有标准的话,可能容器的生命周期仅有几天时间,不适用这种机制。测试相同的指标量,公司存储的方式相对来说比Graphite好一点。因为Graphite是基于文件系统来做的,第一个优化指标名,目录要转存到数据库里做一些索引加速和查询,但是因为容器这边相对通配符比较多,不能直接得知具体对应的ID,只能通配符查询做聚合。因为长期的通配符在字符串的索引上还是易于使用的,所以现在算是折中的做法,把一些常用的查询结果、目录放到里边。

另一个是容器的生命周期。可以做一些审计或者变更的版本,在Mesos层面基于Marathon去监控,发现这些状态后打上标记:当前是哪一个容器或者哪一个TASK出了问题,对应扩容和记录下来。还有Docker自己的问题,这样后面做整个记录时会有一份相对比较完整的TASK-ID。

End.

转载请注明来自36大数据(36dsj.com):36大数据 » 去哪儿网基于Mesos和Docker构建私有云服务的实践

是否存在”可证明”的对于世界的解释?

在对世界进行解释时,科学用的是归纳法,不可证明但是可证伪。宗教,神话等则是既不可证明也不可证伪的。是否存在“可证明”的,对于世界的解释呢?

一般来说,仅根据经验事实就可以确认某个判断为真,这就叫做“证实”(verify),具有这种特征的判断就叫做可证实(verifiability)的。归纳法需要对大量经验事实进行概括才能确认一个判断为真,因此它本质上是在进行证实。与可证实相对的概念是可证伪(falsifiability),也就是我们不能仅根据经验事实确认这个判断为真,但是我们可以确认它的逻辑演绎的后件为假——于是根据否定后件推理,这个判断就为假,这个过程叫证伪。而严格来说,证明(包括逻辑学中的和数学中的)都是指演绎证明,也就是给定公设和公理,然后逻辑演绎得到一个定理,这个叫证明。因此,我们可以说一切只能由归纳法来确认其为真的判断都无法得到证明——因为证明是演绎方法,归纳法则只能导致证实。

另外,关于证实、证伪和证明,我们要注意以下一些问题:
首先,不论是证实还是证伪,它们都只涉及到根据经验事实才能确认其真假的判断。而证明是否涉及经验事实则要看其公设或公理是否需要根据经验事实才能确认其真假。比如由牛顿定律出发的一系列推演和计算都是证明,但牛顿定律本身需要得到证实,因此牛顿力学体系本质上是需要证实的;而由逻辑、数学公理出发的一系列推演在大多数人看来则只需要进行证明,因为大多(即使不是全部)逻辑和数学公理自身不需要经验事实支持即可以为真(但当代有很多自然主义者反对这一点,他们认为所有逻辑和数学公理都是归纳得来的)。如果承认证实+证伪与证明在是否涉及经验这一问题上不同,则我们要注意,尽管证伪和证明都运用了逻辑演绎方法,可是这两者的本质还是完全不同的,比如反证法就不能被视为一种证伪。

其次,证实和证伪方法的适用程度需要根据判断的逻辑特征才能决定。通常的说法就是“全称判断无法证实,存在判断无法证伪”。具体地讲,我们常见的判断在逻辑构造上可以分为以下几种:

1,单称判断,比如某人A于某个时间t处在某个地点p,或者某几个人A、B、C、D于某些时间t1、t2、t3处在某些地点p1、p2、p3等等。这种是关于单一对象的单一状态,或者有限个确定的对象处于一些有限的确定状态的阐述,那么对于这个阐述来说,我们要想知道它是真的话其实很简单,只要在相同环境、相同状态下找到这些人就可以了。而且这些人处在这个环境状态显然是一个经验事实(因为我们可以用感官等感知到),因此它可以得到证实。而且它也可以得到证伪,比如这些人既然有这种状态,那他们肯定不可能瞬间移动到十万八千里外,于是如果在同一时间在另外一个遥远的地方发现这些人,那么也就证伪了这个判断。

2,全称判断,典型的形式是“任意(所有的)的x都是满足F的”(\forall xFx)(比如所有天鹅都是白的)。由于全称判断涉及到取值范围内所有的x,而且取值范围一般都是无穷尽的甚至不确定的,因此我们难以穷尽地获知所有关于x是否满足F的经验事实,它就难以证实。比如“所有天鹅都是白的”,这句话涉及到古往今来乃至未来的任何地方(甚至可能在外星也有可能有天鹅这种生物)所出现的任何一只天鹅,那么我们不管有多强的归纳能力,都不可能知道这么多的天鹅的颜色是否都是白色。

3,存在判断,典型的形式是“存在(有)x,x满足F”(\exists xFx)(比如存在黑洞,地球上至少有十只白天鹅等等)。存在判断只要求取值范围内只要有一个或者有限个对象满足F就可以了,一旦找到这样的经验事实就可以证实该判断;但是要证伪该判断就要穷尽取值范围内所有对象,确认它们的经验事实都不满足该判断,因此难以证伪。从这个角度来说,对存在判断的证伪等价于对其否定的某全称判断的证实(逻辑上即有\neg (\exists x Fx)\leftrightarrow \forall x(\neg Fx));同理,对存在判断的证实等价于对其否定的某全称判断的证伪

科学里面这三种判断都会出现,比如
单称判断:“某时某刻海王星会出现于天区中的某个位置”;
全称判断:常见的科学理论都是全称判断;
存在判断:“存在黑洞”、“存在磁单极子”、“存在Higgs粒子”等等。

因此,对于科学而言,准确的说法是“科学理论不可证实但可以证伪”

总之,我们可以说:
(1)我们可以基于逻辑和数学证明很多判断(至于这些证明需要的公理公设要不要依赖于证实和证伪则另外讨论)。
(2)我们可以证实很多关于世界的经验性判断,包括各种经验性单称判断和存在判断
(3)我们可以证伪很多关于世界的经验性判断,这主要就是以科学理论为代表的经验性全称判断

需要注意的是,所谓“宗教神话不能被证实或证伪”,就相当于已经承诺宗教神话判断所说的内容的真假依赖于经验事实(因此它才需要被证实或证伪),可是这一点很可能不会得到宗教界人士的同意。

对应于题主提到的“是否存在可证实的解释”这个问题。可以说,能够成为一种解释的未必是全称判断,也有一些是对单一事件的单一原因进行解释,这时的解释就可以是单称命题。如果只考虑全称判断式的解释的话,全称判断的来源有很多种:哲学、数学、逻辑、科学、宗教……根据上述总结,则数学和逻辑判断只需要得到证明而不需要证实(除非承认关于数学和逻辑的自然主义);科学中的全称判断只可能被证伪而不能得到证实;宗教、神话中的判断(无论全不全称)不适合于谈论其证明、证实、证伪等方面的特性,除非以逻辑的、哲学和科学等的方式来谈论它。

作者:oldgoat
链接:https://www.zhihu.com/question/23289984/answer/24131288
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

耶鲁教授: 通识教育和思辩培养是中国孩子最缺的两门课

这么多从国内培养出来的杰出高材生,他们在专业上这么突出,但思维方式那么僵化、偏执,社会交往能力又那么差,除了自己狭窄的专业就不知道怎么跟人打交道、怎么表达自己。

如何打造一个日均PV千万级别的大型系统?

作者介绍

周金桥,具有丰富的系统规划、设计、开发、运维及团队组织管理工作经验,熟悉.Net、J2EE技术架构及应用。微软2008-2012五届最有价值专家(MVP),2009年单独著有《ASP.NET夜话》一书,2010年与人合著《程序员的成长之路》。至今活跃在多个技术社区。

本文我选定的方向是如何开发一个大型系统,在这里我对大型系统的定义为日均PV在千万级以上,而京东和淘宝这类则属于巨型系统了。因此在本篇中讲述的都是基于一些开源免费的技术实现,至于通过F5硬件加速、DNS来实现负载均衡、CDN加速等需要花钱购买的技术或者服务则不再本篇介绍范围之类。

一、从两个系统说起

1、某移动互联网公司服务器端架构图

架构

上图是某移动互联网公司的服务器端架构图,它支撑了国内外数百万客户端的访问请求,有如下特点:

  1. 多层级集群,从Web服务器层、NoSQL层级数据库层都实现了集群,这样使得每一层的响应时间大大缩短,从而能够在单位时间内响应更多请求;
  2. NoSQL应用(Memcached),在NoSQL领域Memcached和Redis都有大量的用户群,在这个架构里使用的是Memcached。
  3. 数据库读写分离,当前大多数数据库服务器支持主从机制或订阅发布机制,这样一来就为读写分离创造了条件,减少了数据库竞争死锁出发条件,使响应时间大为缩短(非数据库集群情况下还可以考虑分库机制)。
  4. 负载均衡,Nginx实现Web服务器的负载均衡,Memcached自带负载均衡实现。

2、某公司生产管理系统架构图

系统架构

上图是为某公司的一个分散型系统做的架构设计,这家公司拥有多个跨市、跨省的生产片区,在各片区都有自己的生态车间,各片区与总公司之间通过数据链路连接。这个系统的特点是所有的流水线上的产品都贴有唯一的条码,在生产线的某个操作位操作之前都会扫描贴在产品上的条码,系统会根据条码做一些检查工作,如:产品条码是否应被使用过(比如之前应发货给客户过)、产品是否完成了本道工序之前的全部必须完成工序,如果满足条件则记录当前操作工序名称、操作人、操作时间和操作结果等。

一件产品从上线到完成有数十道工序,而每月下线的产品有少则数十万、多则数百万,一个月下来的数据量也是不小的。特别是在跨厂区网络不稳定的情况下如何保证对生产的影响最小。

本系统架构特点:

  • 所有业务逻辑集中在服务器端,并以Service形式提供,这样便于业务逻辑调整客户端能及时得到最新更新;
  • 部署Service的服务器采用集群部署,Nginx实现调度;
  • NoSQL采用了Redis,与Memcached相比,Redis支持的数据类型更多,同时Redis带有持久化功能,可以将每个条码对应的产品的最终信息存储在Redis当中,这样一般的查询工作(如条码是否被使用、产品当前状态)都可以在Redis中查询而不是数据库查询,这样大大减轻了数据库压力;
  • 数据库采用了主从机制,实现了读写分离,也是为了提高响应速度;
  • 使用了消息队列MQ和ETL,将一些可以异步处理的动作存放在MQ中,然后由ETL来执行(比如订单完成后以邮件形式通知相关人员);
  • 实现了系统监控,通过Zabbix来对服务器、应用及网络关键设备实行7×24小时监控,重大异常及时邮件通知IT支持人员。

由于总部其它地方生产规模较小,所以生产分布未采用复杂架构,不过因为从客户处退回的不良产品都会在总部生产车间进行返修处理,因此总部生产系统需要保存分部生产车间数据,因此分部生产车间数据会同时写进分部生产数据库和分部MQ服务器,然后由总部ETL服务器读取写入到总部系统中。在分部与总部网络中断的情况下分部系统仍可独立工作,直到网络恢复。

二、系统质量保证

1、单元测试

单元测试是指对软件中的最小可测试单元进行检查和验证。通常而言,一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为,常见的开发语言都有对应的单元测试框架,常见的单元测试工具:Junit/Nunit/xUnit.Net/Microsoft.VisualStudio.TestTool

关于单元测试的重要性和如何编写单元测试用例,在本篇就不详述了,网上有大量相关的文章。总之,越大型的系统、越重要的系统,单元测试的重要性越大。

针对一些需要外部依赖的单元测试,比如需要Web容器等,可以使用mock测试,Java测试人员可以使用EasyMock这个测试框架,其网址是http://easymock.org/。

2、代码质量管理平台


对于多人参与的团队项目,虽然大多数情况下会有编码规范拉指导大家如何编写团队风格一致的编码,但不能保证团队中每个成员、尤其是后期加入的团队成员仍能按照编码规范来编写代码,因此需要有一个平台来保证,在这里推荐SonarQube。

SonarQube是一个开源平台,用于管理源代码的质量。Sonar不只是一个质量数据报告工具,更是代码质量管理平台。支持的语言包括:Java、PHP、C#、C、Cobol、PL/SQL、Flex 等。

主要特点:

  • 代码覆盖:通过单元测试,将会显示哪行代码被选中
  • 改善编码规则
  • 搜寻编码规则:按照名字,插件,激活级别和类别进行查询
  • 项目搜寻:按照项目的名字进行查询
  • 对比数据:比较同一张表中的任何测量的趋势

代码

当然除了代码质量管理平台外,还有借助源代码管理系统,并且在每次提交代码前进行代码审核,这样每次代码的异动都可以追溯出来。我管理和经历过的一些重要系统中采用过这样的做法:除了管理所有程序代码之外,还将系统中数据库中的表、视图、函数及存储过程的创建都使用源代码版本管理工具管控起来,而且粒度很小,每个对象的创建都是一个SQL文件。这种方式虽然操作起来有些琐碎,但对于代码的变迁追溯非常方便。

三、系统性能保证

1、缓存


所谓缓存就是将一些频繁使用、但改动相对不平凡的数据保存在内存中,每次更新这些数据的时候同时持久化到数据库或文件系统,并同步更新到缓存中,查询的时候尽可能利用缓存。

缓存的实现方法:自定义实现或利用NoSQL。

  • 自定义实现

自定义实现可利用SDK中提供的类,如Dictionary等。

优点:可以局部提高查询效率;
缺点:不能跨应用、跨服务器,仅限于单个应用;没有较好缓存生命周期管理策略。

  • NoSQL

Memcached

优点:可以跨应用、跨服务器,有灵活的生命周期管理策略;支持高并发;支持分布式。
缺点:不支持持久化,仅在内存存储,重启后数据丢失,需要“热加载”;仅支持Key/Value。

Redis

优点:可以跨应用、跨服务器,有灵活的生命周期管理策略;支持高并发;支持集群;支持持久化;支持Key/Value、List、Set、Hash数据结构;

以上几种方法都存在一个特点:需要通过Key去寻找对应的Value、List、Set或Hash。

除了Memcached和Redis之外,还出现了一些NoSQL数据库和支持NoSQL的数据库,前者如MongoDB,后者如PostgreSQL(>V9.4),下面是一个MongoDB与PostgreSQL的NoSQL特性的对比:

Redis

文档型NoSQL数据库的特点:

  • 不定义表结构

即使不定义表结构,也可以像定义了表结构一样使用,还省去了变更表结构的麻烦。

  • 可以使用复杂的查询条件 


跟键值存储不同的是,面向文档的数据库可以通过复杂的查询条件来获取数据,虽然不具备事务处理和Join这些关系型数据库所具有的处理能力,但初次以外的其他处理基本上都能实现。

NoSQL主要是提高效率,关系数据库可以保证数据安全;各有使用场景,一般的企业管理系统,没多少并发量没必要使用NoSQL,互联网项目或要求并发的NoSQL使用比较多,但是最终重要的数据还是要保存到关系数据库。这也是为什么很多公司会同时使用NoSQL和关系型数据库的原因。

2、异步


所谓异步就是调用一个方法后并不等该方法执行完毕后再继续执行后续的操作,而是调用完毕后马上等待用户的其它指令。打印机管理程序就是一个异步的例子,某个人可能有几个数百页的文档需要打印,可以在打开一个文档之后点击打印,然后继续打开另一个文档继续点打印。尽管打印数百页文档需要较长时间,但后续的打印请求会在打印管理程序中排队,等第一个文档打印完成后再继续第二个文档的打印。

异步有两个层面:编程语言层面的异步和通过消息队列等机制实现的异步。

语法层面异步:像Java/C#等大多数语言都支持异步处理。

  • 消息队列实现异步

用消息队列实现异步只是消息队列的一个基本功能之一,消息队列还具有如下功能:

  • 解耦
  • 灵活性 & 峰值处理能力
  • 可恢复性
  • 送达保证
  • 排序保证
  • 缓冲
  • 理解数据流
  • 异步通信

注:消息队列成为在进程或应用之间进行通信的最好形式。消息队列队列是创建强大的分布式应用的关键。

常用消息队列有如下,可根据系统特点和运维支持团队的掌握程度选择:

  • MSMQ
  • ActiveMQ
  • RabbitMQ
  • ZeroMQ
  • Kafka
  • MetaMQ
  • RocketMQ

3、负载均衡


负载均衡是根据某种负载策略把请求分发到集群中的每一台服务器上,让整个服务器群来处理网站的请求。

常见负载均衡方案

Windows负载均衡:NLB
Linux负载均衡:LVS
Web负载均衡:Nginx
硬件级负载均衡:F5

前面几种都是免费的解决方案,F5作为一种硬件及解决方案在一般企业很少用到。我目前知道的仅有一家世界级饮料公司使用了F5作为负载均衡解决方案,因为这个方案据说相当昂贵。

4、读写分离


读写分离为了确保数据库产品的稳定性,很多数据库拥有双机热备功能。

也就是,第一台数据库服务器,是对外提供增删改业务的生产服务器;第二台数据库服务器,主要进行读的操作。

原理:让主数据库(master)处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库(slave)处理SELECT查询操作。

一般情况下我们是在代码中进行处理,但目前也有不少商业中间件形式的读写分离中间件,能自动将读写数据库操作调度到不同数据库上。

数据库

在大型系统中,有时候主、从数据库都是一个集群,这样可以保证响应速度更快,同时集群中单台服务器故障也不影响整个系统对外的响应。

四、系统安全性保证

1、XSS攻击

  • 防范XSS攻击

XSS攻击类似于SQL注入攻击,攻击之前,我们先找到一个存在XSS漏洞的网站,XSS漏洞分为两种,一种是DOM Based XSS漏洞,另一种是Stored XSS漏洞。理论上,所有可输入的地方没有对输入数据进行处理的话,都会存在XSS漏洞,漏洞的危害取决于攻击代码的威力,攻击代码也不局限于script。

  • DOM Based XSS

DOM Based XSS是一种基于网页DOM结构的攻击,该攻击特点是中招的人是少数人。

  • Stored XSS

Stored XSS是存储式XSS漏洞,由于其攻击代码已经存储到服务器上或者数据库中,所以受害者是很多人。假如有两个页面,一个负责提交内容,一个负责将提交的内容(论坛发帖、读帖就是这种形式的典型):

提交内容:
页面内容:<%=request.getParameter(“content”)%>

这样用户在a站提交的东西,在显示的时候如果不加以处理就会打开b站页面将相关敏感内容显示出来。

针对XSS攻击的防范办法:

Html encode
特殊字符过滤:<,>

2、SQL注入

  • SQL Injection

所谓SQL注入式攻击,就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令。在某些表单中,用户输入的内容直接用来构造(或者影响)动态SQL命令,或作为存储过程的输入参数,这类表单特别容易受到SQL注入式攻击。

例如我们在登录一个系统时,在软件底层按照如下方式查询数据:

登录SQL语句:

SELECT COUNT(*) FROM Login WHERE UserName=’admin’ AND Password=’123456‘
SELECT COUNT(*) FROM Login
WHERE UserName=’admin’–
Password=’123′

SQL

针对SQL注入防范办法:

  • 数据输入验证
  • 特殊字符过滤:特殊字符过滤
  • 参数化SQL语句(包括存储过程)
  • 不使用sa级别账户作为连接账户或限制连接IP

3、CSRF攻击


CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,并且攻击方式几乎相左。XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。

其核心策略是利用了浏览器Cookie或者服务器Session策略,盗取用户身份。
针对CSRF攻击防范办法:

  • 表单Token
  • 验证码
  • Referer检查
  • 关键操作身份确认

4、其它攻击


Error Code:即错误代码回显,许多Web服务器为调试方便默认显示详尽错误信息,如错误发生的上下文、服务器及应用信息等,容易被恶意利用。

系统或者框架漏洞:如IIS6.0以下版本存在“JPG漏洞”;Apache Struts2服务在开启动态方法调用任意方法漏洞(CVE-2016-3081);OpenSSL的heartbeat漏洞(CVE-2014-0160);Apache解析漏洞;Nginx(

  • 上传文件时对MIME进行检查,必要情况下对上传文件更名
  • 及时关注安全网站及产品官方网站,发现漏洞及时打补丁
  • 对Web Server运用的用户角色权限进行限制
  • 使用漏洞扫描工具模拟攻击
  • 下面是一些我见过的被攻击后的系统截图,如下图是CCTV音乐频道被攻击的截图:

    还有本人2008年前后搭建PHPWind运行的画面:

    PHPWind

    上图中是本人2006年前后搭建的一个论坛,有人利用系统漏洞注册了很多用户名为空的用户(其实是身份遗失),,然后又利用这些账户在论坛中大量发布广告、色情等违法违纪的帖子,因为使用了一些不可见字符进行注册的,在后台无法管理,最后只好在数据库中操作管理了。

    五、开发相关的经验教训

    1、应用日志记录

    以前团队运维着一个老系统,系统中没有日志功能,而系统的操作人员的计算机水平又较低,每次打电话都是说系统不能用或者是一些根本无法快速定位原因的描述,每次接到求助后需要花费大量时间来分析定位原因,后来将系统中增加了日志功能,并且在网络状态连通情况下可自动将错误日志以邮件形式发送到负责同事组成的用户组,自此以后处理这类问题的响应时间大大缩短了,双方都很满意。

    现在已经有很多开源日志库,比如.NET的Log4Net,Java的Log4j,可以很轻松地配置启用日志功能。利用日志组件可以将信息记录到文件或数据库,便于发现问题时根据上下文环境发现问题,这一点在调试多线程时尤其重要。

    日志级别:FATAL(致命错误)、ERROR(一般错误)、WARN(警告)、INFO(一般信息)、DEBUG(调试信息)。

    注意:在调试环境中时日志级别尽量低(warn/info),在生产环境中日志级别尽量高(error),且对日志文件大小一定要进行控制。不然也会产生问题。

    案例:某国内有名的管业集团公司的一个系统的重要模块发生问题,启用了日志功能以便通过日志组件快速将问题定位并修复。在发布到生产环境时,运行一段时间之后发现程序运行效率相当低下,多位开发人员对模块代码进行性能分析未发现问题,大家发现同样的数据量和操作在生产环境和开发环境效率差巨大,无意中发现生产服务器上日志文件已超过5G!事后发现是由于疏忽未调高日志级别且未对日志进行控制,调整日志模式为按日记录,问题解除。

    参考:《log4net使用详解》 http://blog.csdn.net/zhoufoxcn/article/details/222053

    2、历史记录追踪

    • 代码管控

    尽可能使用代码管控工具对源代码进行管控,如SVN/TFS/Git,如果有可能不但管控程序代码,还要管控数据库相关的SQL文件(包括初始化脚本及存储过程和使用ORM框架中的Mapping文件),做到系统的一切变动皆有记录。

    • 代码审核

    任何人提交代码都必须本人本地编译、调试无误后,再有人review后方可提交,且针对bug修复的提交需注明所修复的bug信息。

    • Bug记录

    通过Bug记录系统记录整个bug的生命周期,包括发现、修复、关闭。TFS本身支持bug记录,开源系统中禅道也是一个不错的Bug记录工具。

    六、总结

    本篇主要是就系统从开发到最终部署运维过程中常用的技术、框架和方法做了一个总结,当然以上经验总结来源于本人从业以来所经历的项目中的经验和教训,可能还有更好更完美的方案,在此权当抛砖引玉

    from:http://www.yunweipai.com/archives/22697.html

    algorithm

    stackoverflow algorithm

    Sorting 1 million 8-digit numbers in 1 MB of RAM

    Write a program to find 100 largest numbers out of an array of 1 billion numbers

    Why is quicksort better than mergesort?

    Best way to reverse a string

    What is a plain English explanation of “Big O” notation?

    面试10大算法汇总+常见题目解答

    面试常见十大类算法汇总

    大数据量的算法面试题

    Bloom filter:大数据快速排除算法

    海量数据处理常见面试题

    十道海量数据处理面试题与十个方法大总结

    教你如何迅速秒杀99%的海量数据处理面试题

    十五道海量数据处理面试题与Bit-map详解

     

    Here is a website on good algorithms and technical interviews.

    Website: IDeserve

    What algorithms and data structures should any software engineer know?

    What are some good blogs about algorithms and technical interviews?

     

     

    WcBRI