转个段子:今日头条公司福利待遇遇好是一种怎样的体验

在教育培训机构当老师是一种怎样的体验? - 知乎1718被浏览994963分享邀请回答22872 条评论分享收藏感谢收起78110 条评论分享收藏感谢收起查看更多回答面向工资编程 - 知乎专栏
{"debug":false,"apiRoot":"","paySDK":"/api/js","wechatConfigAPI":"/api/wechat/jssdkconfig","name":"production","instance":"column","tokens":{"X-XSRF-TOKEN":null,"X-UDID":null,"Authorization":"oauth c3cef7c66aa9e6a1e3160e20"}}
{"database":{"Post":{"":{"title":"搬个小板凳,我们扯扯Docker的前生","author":"auxten","content":"新瓶装旧酒首先我们需要知道,Docker是一个“箩筐”:存储:Device Mapper、BtrFS、AUFS名字空间:UTS、IPC、Mount、PID、Network、User网络:Veth、Bridge、IptablesCgroups:CPU、CPUset、Memory、Device安全:Capability、SELinux、Seccomp……又是Jeffrey DeanDocker的诞生其实跟Google有很大的渊源:那年,Jeffrey Dean还是一枚鲜肉。众所周知MapReduce是现在通用大数据处理的理论基石,在Jeffrey Dean提出这个模型后,Google内部率先用这个模型在内部实现了大数据计算的统一模型。Jeffrey Dean在2004年的OSDI(Operating Systems Design and Implementation)会议上发表MapReduce论文之后,Hadoop按图索骥慢慢成为了开源界最为流行的大数据处理框架。甚至在后面,Hadoop变成了一个生态系统和Android一起养活了一大批Java程序员。Java程序在饭前都祷告:“噢,感谢伟大的Hadoop,感谢Android赐予我们食物,Amen!”\n但和Hadoop不一样的一点是:Hadoop需要搭建专属的集群,而Google的MapReduce离线计算是和线上的业务是共享计算资源的。首先说一下Google这么做的必要性:绝大多数线上的业务的繁忙程度是和业务类型、用户的作息、地理位置相关的。\n例如:在中国`11.11`是一个大日子,所有电商都拼了命的在搞促销,而在欧美国家与之相对应是圣诞节;传统的办法为了应对高峰期的流量往往要预备很多硬件资源备用,但这些资源在平时基本上是闲置状态。对于更新速度极快的IT设备来说,闲置就是浪费。\nGoogle这样做的好处自然是能大大的提高计算资源的利用率。但之所以大多数公司没有这么做,是由于Linux Kernel对资源(CPU、内存、I/O)隔离设施的缺乏。谁也不愿意看到一个日志挖掘的任务导致线上业务宕机。Google爸爸改内核但Google毕竟是Google,Kernel不支持,那就改Kernel!!于是Google的工程师就在Kernel里增加了一种可以做资源隔离的设施:Control Groups,再配合chroot实现了一套较为完善的机制来保证进程之间可以不互相影响。作为这套系统的某后英雄之一的Borg就是Google内部的分布式计算调度系统,负责统一调度各种MapReduce的资源分配和线上服务。当时Google之所以选择了这条路,也一定程度上是由于Xen、KVM这些虚拟化技术还不成熟。但即使后来外面的公司广泛的用Xen、KVM来做资源隔离,Google也并没有跟风,正是因为Google的这种方式省去了额外的Hypervisor和Guest OS的开销,可以达到更高的资源利用率。Google Borg rocks!Google几乎所有的机器都是混部的,在一台机器上,可能运行着不同jobs的tasks。根据Google在Borg论文里披露的数据:Google的50%的机器运行了9个甚至更多的tasks;90%的机器运行着25个tasks,达到4500个线程。\n当然Google也并不排斥KVM、Xen等虚拟化技术。对于外部运行在GAE(Google App Engine)和GCE(Google Compute Engine?)上的代码,Google的做法就是让它们运行在虚拟机(KVM)上,KVM进程被作为Borg的task运行。也就是说,Borg是作为下层的,KVM运行在它之上。资源隔离机制在Google内部使用的比较稳定了之后,就被毫无保留地贡献给了开源社区,并把它命名为Cgroups。DockerCgroups出现后,Docker所需要的各种原材料就齐备了:2010年,几个雄心勃勃的年轻人怀揣1000万美元的融资在旧金山成立了一家做PaaS平台的公司,起名为dotCloud。目标是做世界上最好的PaaS,打败他们:Amazon AWSGoogle GAEIBM BluemixRedHat OpenShiftMicrosoft AzureVMware Cloud FoundryHeroku……面对这些动辄千亿市值的大佬,绝大多数人都跟他们说:『呵呵?』。在苦苦支撑了几年之后,公司业务始终不见起色。dotCloud的创始人Solomon Hykes决定把dotCloud的所有源代码开源来搏一把。 没想到,他们的核心引擎Docker重现了当年Linux Kernel开源时的丰彩,获得了广大服务端程序员的追捧:“这个容器管理引擎大大降低了容器技术的使用门槛,轻量级,可移植,虚拟化,语言无关,写了程序扔上去做成镜像可以随处部署和运行,开发、测试和生产环境彻底统一了,还能进行资源管控和虚拟化。”于是,dotCloud迅速停下其它手中业务的开发,开始专心研发Docker产品和维护相关社区,过上了幸福而快乐的生活。后面甚至把公司名字都改成Docker,2014年8月Docker宣布把PaaS的业务dotCloud出售给位于德国柏林的PaaS提供商CloudControl,dotCloud的历史告一段落,Docker的序幕缓缓拉开……Golang 技术交流群:","updated":"T12:34:12.000Z","canComment":false,"commentPermission":"anyone","commentCount":16,"likeCount":86,"state":"published","isLiked":false,"slug":"","isTitleImageFullScreen":false,"rating":"none","sourceUrl":"","publishedTime":"T20:34:12+08:00","links":{"comments":"/api/posts//comments"},"url":"/p/","titleImage":"/v2-38a276dfad87b_r.png","summary":"","href":"/api/posts/","meta":{"previous":null,"next":null},"snapshotUrl":"","commentsCount":16,"likesCount":86},"":{"title":"技术分享丨关于 Hadoop 的那些事儿","author":"xin-zhu-84-58","content":"介绍Hadoop的文章已经很多了,个人感觉这一篇还是写得不错的:Hadoop以前是,现在仍然是大数据批处理领域的王者。Hadoop逐渐完善的生态体系,也让Hadoop广泛应用于各行业。本文首先介绍Hadoop的架构和原理,侧重于Map-Reduce计算部分。再以简单示例带大家入门。一、Hadoop 介绍Hadoop 是什么Hadoop是一个开发和运行大规模数据分析程序的软件平台,是隶属Apache的一个用java语言实现的开源软件框架,在大量普通服务器组成的集群中对海量数据进行分布式计算。a java based software framework for easily writing applicationswhich process vast amounts of data (multi-petabyte data-sets)in-parallel on large clusters (thousands of nodes) of commodity hardwarein a reliable, fault-tolerant manner.Hadoop 生态圈HDFS——Hadoop生态圈的基本组成部分是Hadoop分布式文件系统(HDFS)。HDFS是一种数据分布式保存机制,数据被保存在计算机集群上。HDFS为HBase等系统提供了基础。MapReduce——Hadoop的主要执行框架是MapReduce,它是一个分布式、并行处理的编程模型。MapReduce把任务分为map(映射)阶段和reduce(化简)。开发人员基于存储在HDFS中数据,编写Hadoop的MapReduce任务。由于MapReduce工作原理的特性, Hadoop能以并行的方式访问数据,从而实现快速访问数据。Hbase——HBase是一个建立在HDFS之上,面向列的NoSQL数据库,用于快速读/写大量数据。HBase使用Zookeeper进行管理,确保所有组件都正常运行。Zookeeper——用于Hadoop的分布式协调服务。Hadoop的许多组件依赖于Zookeeper,它运行在计算机集群上面,用于管理Hadoop操作。Oozie——Oozie是一个可扩展的工作体系,集成于Hadoop的堆栈,用于协调多个MapReduce作业的执行。它能够管理一个复杂的系统,基于外部事件来执行,外部事件包括数据的定时和数据的产出。Pig——它是MapReduce编程的复杂性的抽象。Pig平台包括运行环境和用于分析Hadoop数据集的脚本语言(Pig Latin)。其编译器将PigLatin翻译成MapReduce程序序列。Hive——Hive类似于SQL高级语言,用于运行基于Hadoop的查询语句,Hive让不熟悉MapReduce开发人员也能编写数据查询语句,然后这些语句被翻译为Hadoop上面的MapReduce任务。像Pig一样,Hive作为一个抽象层工具,吸引了很多熟悉SQL而不是Java编程的数据分析师。Hadoop的生态圈还包括以下几个框架,用来与其它企业融合:Sqoop是一个连接工具,用于在关系数据库、数据仓库和Hadoop之间转移数据。Sqoop利用数据库技术描述架构,进行数据的导入/导出;利用MapReduce实现并行化运行和容错技术。Flume提供了分布式、可靠、高效的服务,用于收集、汇总大数据,并将单台计算机的大量数据转移到HDFS。它基于一个简单而灵活的架构,并提供了数据流的流。它利用简单的可扩展的数据模型,将企业中多台计算机上的数据转移到Hadoop。Hadoop历史o Apache社区的开源分布式系统o
Google发布GFS/ MapReduce论文o 2006, Doug Cutting创立Apache Hadoopo 2008, release 0.19.0o 2009, release 0.20.0 -& 0.20.20x (生产系统稳定版本)o 201111, release 0.23.0 alpha -& .0.0 alphao .20.20x -& release 1.0.0o 商业公司支持:Cloudera & HortonworksWho use HadoopHadoop程序的研发流程Hadoop的构架第一代Hadoop架构如下:HDFS介绍HDFS基本操作hadoop fs –ls
显示hdfs指定路径下的文件和文件夹hadoop fs –putmy_file
将本地文件上传到hdfshadoop fs –get/tmp /data/my_file
将hdfs上的文件下载到本地hadoop fs
–cat /tmp /data/my_file
查看dfs中的文本文件内容hadoop fs
–text /tmp /data/my_sequence_file
查看dfs中的sequence文件内容hadoop fs –rm /tmp/data/my_file
将hdfs上的文件删除二、MapReduce 原理MapReduce – 模型原理原理是分治思想,把一件事情先分解处理,然后再把处理后的结果合并。Map阶段就是分解处理,reduce阶段合并:分治思想分解、求解合并MapReduce映射分:map合:reduce举个例子,有一堆的商品,共M种,需要数一下每种商品的个数。传统的做法是,找一个人,数所有的商品,得出结果,如果觉得不够快,那就换一个数的更快的人(分布式计算出现以前的思路)。随着商品数量的增加,单个人数商品的做法,已不太可行。基于MR计算模型,可以采用的方案是:找N个人,每人分一堆商品,每人都各自统计自己的商品,M种中每种有多少;然后再找M个人,每个人负责一种商品,把前面N个人的统计结果进行汇总。总之,数据可以切割的计算,都可以用 Hadoop 实现。MapReduce – 调度框架这张图展示了MapReduce的调度框架,主要有这几个角色:JobClient、JobTracker、TaskTracker,这里面的JT是一个单Master节点,TT是部署在每台计算节点上的一个Service。其中JobClient负责根据用户指定的参数,生成一个MapReduce作业,然后把作业提交到JobTracker,JT负责把Job所有的Task调度到TT上。MapReduce – 执行层这个图展示了一个Mapreduce的执行过程,是一个具体的执行单元内(Task)发生的事情。左边是Map Task,map task的输入是一个数据分片,叫一个split。输入数据由 MapReduce 框架解析成一条条记录,这是一个按照用户指定的规则(或者是默认规则)读取数据的过程。读取出的数据,将他们一条条的传给map处理,就是大家写的mapper函数经过mapper 处理后,又生成一条新记录,写在mapper所在机器的本地磁盘,分Partition写入,不同Partition数据会交由不同reduce处理;右边是Reduce Task,Rt运行起来后先做的事情就是把属于自己的那一份份数据给拉到自己本地来,这个过程叫shuffle,shuffle的具体过程很复杂,其中包括各种异常处理,性能优化点也比较多。数据shuffle到reduce本地之后,和map类似,一条条交给reduce函数处理,然后按照用户指定的格式写到HDFS指定目录。MapReduce – 开发方式1.基于java开发
--优势:原生接口,功能完备,性能较高2.Streaming开发
--优势:不限语言,实现简单三、Streaming 作业举例Streaming 原理Hadoop Streaming通过标准输入将数据传递给用户实现的map/reduce程序,map/reduce程序使用标准输出将数据返回给Hadoop框架。词频统计 – 示例词频统计 – Shell实现Streaming - 本地调试Streaming最大的优点就是写起来方便,Streaming作业的本地调试的方法如下:把输入数据用cat命令送到管道,管道另一头接mapper程序,输出重定向到文件,用sort命令把输出数据排序。然后再把以排过序的数据通过管道送给reducer程序,最后保存结果得到输出数据。mapcat input | sh mapper.sh & map.outsortsort map.out & map.sortreducecat map.sort | sh reducer.sh & reduce.out四、第二代 Hadoop 架构Hadoop1 存在的问题Hadoop1存在的问题,主要有这么几方面:1、可用性,JobTracker是单点,升级中断服务,正在运行的作业会失败;2、扩展性,因为JobTracker单点性能瓶颈,单机群最大规模也就是几千台3、按槽位分task,集群整体资源利用率不高,因为每台机器上运行多少个Task是固定的,但是每个Task消耗的资源,其实差异很大。Hadoop2与Hadoop1的对比 Hadoop2 计算架构 Hadoop1计算部分,主要有两个角色,JT和TT,其中JT是单点。Hadoop2把单点的JT角色做了分布式化:分布式化成包括RM 和AM两个角色,其中RM是单点,而AM是每个job一个,不同job之间是独立的AM。这样,作业级别的调度在RM,Task级别的调度在AM,大大减轻了RM的压力:RM:资源管理AM:负责具体某一个作业的运行,申请Task资源,调度Task调度AS:相当于之前的TT,但是每个机器上可以同时运行多个AS,每个AS同时只运行一个Task,理解为一个槽位。Hadoo2的主要优势有:1、支持热升级中断时间很短,对用户基本透明2、支持更大规模的集群集群规模可超过万台3、更高的集群资源利用率淡化槽位概念,更细粒度资源&cpu, memory&五、分享交流1、想要参加“技术沙龙-周五课堂”的小伙伴请加群:Reboot 周五分享群 2、报名请联系:Ada:小夏:运维开发交流QQ群: 欢迎大家关注公共号,高品质运维开发关于Reboot:专注于互联网运维开发分享、交流,让更多的运维工程师更加专注于自动化,为国内公有云开发、监控、运维贡献自己的力量。这里聚集着国内一线互联网工程师,乐于分享与交流 。发现文章不错的话请关注我们。我的博客:","updated":"T03:23:33.000Z","canComment":false,"commentPermission":"anyone","commentCount":2,"likeCount":121,"state":"published","isLiked":false,"slug":"","isTitleImageFullScreen":false,"rating":"none","sourceUrl":"","publishedTime":"T11:23:33+08:00","links":{"comments":"/api/posts//comments"},"url":"/p/","titleImage":"/682de202e36dcd_r.jpg","summary":"","href":"/api/posts/","meta":{"previous":null,"next":null},"snapshotUrl":"","commentsCount":2,"likesCount":121},"":{"title":"技术分享丨HDFS 入门","author":"xin-zhu-84-58","content":"在介绍HDFS之前要说的相关背景资料Hadoop:一个分布式系统基础架构,由Apache基金会开发。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力高速运算和存储。Distributed:分布式计算是利用互联网上的计算机的 CPU 的共同处理能力来解决大型计算问题的一种计算科学。File system:文件系统是操作系统用于明确磁盘或分区上的文件的方法和数据结构;即在磁盘上组织文件的方法。也指用于存储文件的磁盘或分区,或文件系统种类。Hadoop 和 HDFS 的关系Hadoop实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS。对外部客户机而言,HDFS 就像一个传统的分级文件系统。可以创建、删除、移动或重命名文件,等等。很多时候,我们就叫它DFS(Distributed\nFile System)。Hadoop 是一个以一种可靠、高效、可伸缩的方式进行处理的,能够对大量数据进行分布式处理的系统框架。HDFS是Hadoop兼容最好的标准级文件系统,因为Hadoop是一个综合性的文件系统抽象,所以HDFS不是Hadoop必需的。所以可以理解为Hadoop是一个框架,HDFS是Hadoop中的一个部件。我们为什么需要HDFS要说明需要HDFS,首先得说明一下,为什么在计算机系统中需要文件系统。操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。简单的理解为,只要有文件管理,就得有文件系统。文件系统由三部分组成:与文件管理有关软件、被管理文件以及实施文件管理所需数据结构。从系统角度来看,文件系统是对文件存储器空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统。文件系统是用于存储文件的,但是我们发现现有的文件系统忙于处理什么文件呢?看起来现有的磁盘能够胜任目前的数据处理,但对于我们来说有一个好消息和坏消息。磁盘面对的海量信息有证券交易所的每天1TB的信息;社交网站上2PB的图片;计算机每天产生的100GB到10TB的机器日志,缓存文件,RFID检测器等等。既然读取一块磁盘的所有数据需要很长时间,写入更是需要更长时间(写入时间一般是读取时间的3倍)。我们需要一个巨大文件难道得换传输速度10GB/S的磁盘(现在没有这样的磁盘),而且即使有文件为1ZB,或者小点10EB时,这样的磁盘也无法做到随读随取。当数据集的大小超过一台独立物理计算机的存储能力时,就有必要对它进行分区并存储到若干台单独的计算机上。从概念图上看,分布化的文件系统会因为分布后的结构不完整,导致系统复杂度加大,并且引入的网络编程,同样导致分布式文件系统更加复杂。对于以上的问题我们来HDFS是如何迎刃而解的:HDFS以流处理访问模式来存储文件的。一次写入,多次读取。数据源通常由源生成或从数据源直接复制而来,接着长时间在此数据集上进行各类分析,大数据不需要搬来搬去。DFS是用流处理方式处理文件,每个文件在系统里都能找到它的本地化映像,所以对于用户来说,别管文件是什么格式的,也不用在意被分到哪里,只管从DFS里取出就可以了。一般来说,文件处理过程中无法保证文件安全顺利到达,传统文件系统是使用本地校验方式保证数据完整,文件被散后,难道需要特意安排每个分片文件的校验码?HDFS的回答是:NO!分片数量和大小是不确定的,海量的数据本来就需要海量的校验过程,分片后加入每个分片的跟踪校验完全是在数满天恒星的同时数了他们的行星。HDFS的解决方案是分片冗余,本地校验。直观上看,我们是给文件系统添堵,文件越来越多,实际上,DFS更加喜欢这样的架构。数据冗余式存储,直接将多份的分片文件交给分片后的存储服务器去校验。冗余后的分片文件还有个额外功能,只要冗余的分片文件中有一份是完整的,经过多次协同调整后,其他分片文件也将完整。经过协调校验,无论是传输错误,I/O错误,还是个别服务器宕机,整个系统里的文件是完整的。分布后的文件系统有个无法回避的问题,因为文件不在一个磁盘导致读取访问操作的延时,这个是HDFS现在遇到的主要问题。现阶段,HDFS的配置是按照高数据吞吐量优化的,可能会以高时间延时为代价。但万幸的是,HDFS是具有很高弹性,可以针对具体应用再优化。HDFS 的概念通过上一节的得到的信息,我们了解了HDFS就是下面这个抽象图的具体实现:解释一下,何为元数据:元数据是用于描述要素、数据集或数据集系列的内容、覆盖范围、质量、管理方式、数据的所有者、数据的提供方式等有关的信息。更简单的说,是关于数据的数据。HDFS就是将巨大的数据变成大量数据的数据。磁盘存储文件时,是按照数据块来存储的,也就是说,数据块是磁盘的读/写最小单位。数据块也称磁盘块。构建于单个磁盘上的文件系统是通过磁盘块来管理文件系统,一般来说,文件系统块的大小是磁盘块的整数倍。特别的,单个磁盘文件系统,小于磁盘块的文件会占用整个磁盘块。磁盘块的大小一般是512字节。在HDFS中,也有块(block)这个概念,默认为64MB,每个块作为独立的存储单元。与其他文件系统不一样,HDFS中每个小于块大小的文件不会占据整个块的空间。具体原因在后面的介绍。下面介绍为什么是64MB一个文件块:为什么HDFS中的小文件不会占用整个块,而且需要64MB或者更大的一个块?在文件系统中,系统存储文件时,需要定位该数据在磁盘中的位置,再进行传输处理。定位在磁盘的位置是需要时间的,同样文件传输也是需要时间。T(存储时间)=T(定位时间)+T(传输时间)如果每个要传输的块设置得足够大,那么从磁盘传输数据的时间可以明显大于定位这个块开始位置的时间。当然不是设置每个块越大越好。HDFS提供给MapReduce数据服务,而一般来说MapReduce的Map任务通常一次处理一个块中的数据,如果任务数太少(少于集群中节点的数量),就没有发挥多节点的优势,甚至作业的运行速度就会和单节点一样。分布式的文件抽象能够带来的优势是:1、一个文件可以大于每个磁盘2、文件不用全在一个磁盘上。3、简化了存储子系统的设计。其实,HDFS对与用户来说,可以直接看成是一个巨大的硬盘所以,HDFS和文件系统相似,用fsck指令可以显示块信息:% hadoop fsck / -files -blocksHDFS 的关键运行机制HDFS是基于主从结构(master/slaver)构件:在HDFS的主从结构中,有两类节点 namenode和datanode。他们以管理者-工作者模式工作。子节点才是HDFS真正的存储和检索地点,如果想在主节点做整个集群数据的索引并检索的话,请考虑可行性,毕竟HDFS不擅长做巨型索引。客户端(client)代表用户通过与namenode和datanode交互访问整个文件系统。可以是具体程序,也可以是应用。所以,用户在编程时,无需知道namenode和datanode也可以实现功能。没有datanode,文件系统不会崩溃,文件系统只是无法存储文件,也不会丢失数据。没有namenode,文件系统会崩溃,文件系统上的所有文件将丢失(无法读出,因为无法定位元数据块的位置,也就无法根据datanode的块来重构文件)。如何使用HDFSHDFS是在安装并成功配置后即可使用。具体安装过程不再赘述。无论是使用shell脚本,或者使用WEB UI进行操作,使用前必须得明白HDFS的配置。便于存储操作或者操作优化。例如我们使用伪分布式配置(也就是1个namenode和1个datanode配置方式)。说明hdfs的URI是localhost,hdfs的守护进程将通过该属性确定namenode的主机和端口。分布式文件系统将文件存储为1份备份。常用HDFS命令分享和交流想要参加“技术沙龙-周五课堂”的小伙伴请加群:Reboot 周五分享群 周五分享预告: 05月27日
晚上21:00主题:浅析ceph主讲人:前360分布式攻城狮内容:解开Ceph神秘的面纱Ceph工作原理及流程Ceph 日常维护及常用操作运维开发交流QQ群: 欢迎大家关注公共号,高品质运维开发关于Reboot:专注于互联网运维开发分享、交流,让更多的运维工程师更加专注于自动化,为国内公有云开发、监控、运维贡献自己的力量。这里聚集着国内一线互联网工程师,乐于分享与交流 。发现文章不错的话请关注我们。","updated":"T09:09:59.000Z","canComment":false,"commentPermission":"anyone","commentCount":1,"likeCount":54,"state":"published","isLiked":false,"slug":"","isTitleImageFullScreen":false,"rating":"none","sourceUrl":"","publishedTime":"T17:09:59+08:00","links":{"comments":"/api/posts//comments"},"url":"/p/","titleImage":"/e29f73a896_r.png","summary":"","href":"/api/posts/","meta":{"previous":null,"next":null},"snapshotUrl":"","commentsCount":1,"likesCount":54},"":{"title":"戏说守护、僵尸、孤儿进程","author":"auxten","content":"首先说简单的结论:没有父进程的进程就是孤儿进程,孤儿进程会被init领养,成为一个准守护进程。如果进程他爹活着,但是不给子进程收尸(wait、waitpid),子进程就会变成僵尸。守护进程(Daemon)是在一类脱离终端在后台执行的程序, 通常以 d 结尾, 随系统启动, 其父进程 (ppid) 通常是 init 进程以下是Wikipedia中关于Daemon的定义:In multitasking computer operating systems, a daemon (/'di:m?n/ or /'de?m?n/) is a computer program that runs as a background process, rather than being under the direct control of an interactive user. Traditionally daemon names end with the letter d: for example, syslogd is the daemon that implements the system logging facility and sshd is a daemon that services incoming SSH connections.一般要让当前程序以守护进程形式运行, 在命令后加 & 并重定向输出即可:$ nohup some_program & /dev/null 2&&1 &这是直接运行程序的方式, 如果是用具体语言代码的形式来实现呢, 总的来说守护进程应该有以下几个特征:后台运行也就是不占用console的前面,也就是bash里运行程序后面加个&成为process group leaderProcess Group Leader就是父进程是init的那个进程。成为session leader一个ssh登录会启动一个bash,bash会fork出很多子进程,这些进程轮流接手tty输出。这都是属于一个session。 session leader就是这一堆进程的父进程。fork一次或者两次fork 两次是出于被当成库调用的考虑。chdir到/防止占用别的路径的working dir的fd,导致一些block不能unmountumask需要重置umask,防止后续子进程继承非默认umask造成奇怪的行为。处理标准输入输出,错误输出(0,1,2)重定向stdout、stderr、stdin,防止tty中断后的broken pipe信号。日志输出重定向后,需要有办法反映内部情况。信号处理最后最好对将一些终端相关的信号处理忽略一下,防止受到相关信号导致的进程退出。例如:SIGHUP、SIGTTIN、SIGTTOU。这是很多没有经验的菜鸟容易忽略的点。一般nohup命令会帮我们处理。用下面的代码就可以实现一个非常规范的守护进程(代码注释很详细但有点长):#!/usr/bin/env python\n\nimport sys, os, time, atexit\nfrom signal import SIGTERM\n\nclass Daemon:\n
A generic daemon class.\n
Usage: subclass the Daemon class and override the run() method\n
def __init__(self, pidfile='nbMon.pid', stdin='/dev/null', stdout='nbMon.log', stderr='nbMon.log'):\n
self.stdin = stdin\n
self.stdout = stdout\n
self.stderr = stderr\n
self.pidfile = pidfile\n
def daemonize(self):\n
do the UNIX double-fork magic, see Stevens' \"Advanced\n
Programming in the UNIX Environment\" for details (ISBN )\n
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16\n
pid = os.fork()\n
if pid & 0:\n
# exit first parent\n
sys.exit(0)\n
except OSError, e:\n
sys.stderr.write(\"fork #1 failed: %d (%s)\\n\" % (e.errno, e.strerror))\n
sys.exit(1)\n
# decouple from parent environment\n
#os.chdir(\"/\")\n
os.setsid()\n
os.umask(0)\n
# do second fork\n
pid = os.fork()\n
if pid & 0:\n
# exit from second parent\n
sys.exit(0)\n
except OSError, e:\n
sys.stderr.write(\"fork #2 failed: %d (%s)\\n\" % (e.errno, e.strerror))\n
sys.exit(1)\n
# redirect standard file descriptors\n
sys.stdout.flush()\n
sys.stderr.flush()\n
si = file(self.stdin, 'r')\n
so = file(self.stdout, 'a+')\n
se = file(self.stderr, 'a+', 0)\n
os.dup2(si.fileno(), sys.stdin.fileno())\n
os.dup2(so.fileno(), sys.stdout.fileno())\n
os.dup2(se.fileno(), sys.stderr.fileno())\n
# write pidfile\n
atexit.register(self.delpid)\n
pid = str(os.getpid())\n
file(self.pidfile,'w+').write(\"%s\\n\" % pid)\n
def delpid(self):\n
os.remove(self.pidfile)\n\n
def start(self):\n
Start the daemon\n
# Check for a pidfile to see if the daemon already runs\n
pf = file(self.pidfile,'r')\n
pid = int(pf.read().strip())\n
pf.close()\n
except IOError:\n
pid = None\n
message = \"pidfile %s already exist. Daemon already running?\\n\"\n
sys.stderr.write(message % self.pidfile)\n
sys.exit(1)\n
# Start the daemon\n
self.daemonize()\n
self.run()\n\n
def stop(self):\n
Stop the daemon\n
# Get the pid from the pidfile\n
pf = file(self.pidfile,'r')\n
pid = int(pf.read().strip())\n
pf.close()\n
except IOError:\n
pid = None\n
if not pid:\n
message = \"pidfile %s does not exist. Daemon not running?\\n\"\n
sys.stderr.write(message % self.pidfile)\n
return # not an error in a restart\n\n
# Try killing the daemon process
while 1:\n
os.kill(pid, SIGTERM)\n
time.sleep(0.1)\n
except OSError, err:\n
err = str(err)\n
if err.find(\"No such process\") & 0:\n
if os.path.exists(self.pidfile):\n
os.remove(self.pidfile)\n
print str(err)\n
sys.exit(1)\n\n
def restart(self):\n
Restart the daemon\n
self.stop()\n
self.start()\n\n
def run(self):\n
You should override this method when you subclass Daemon. It will be called after the process has been\n
daemonized by start() or restart().\n
\"\"\"\n\n可以看一个示例:#!/usr/bin/env python\n# coding=utf-8\n\nfrom daemon import Daemon\nimport socket\nimport time\n\nhtml = \"\"\"HTTP/1.1 200 OK\\r\\nContent-Type: image/jpeg\\r\\nConnection: close\\r\\nContent-Length: \"\"\"\nhtml404 = \"\"\"HTTP/1.1 404 Not Found\\r\\nContent-Type: text/html\\r\\nContent-Length: 13\\r\\n\\r\\n&h1&404 &/h1&\"\"\"\n\nclass agentD(Daemon):\n
def run(self):\n
listen_fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)\n
listen_fd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n
listen_fd.bind((\"0.0.0.0\", 9000))\n
listen_fd.listen(10)\n
while True:\n
conn, addr = listen_fd.accept()\n
print \"coming\", conn, addr\n
read_data = conn.recv(10000)\n
#print read_data\n
pic_name = read_data.split(\" \")[1][1:]\n
print pic_name\n
with file(pic_name) as f:\n
pic_content = f.read()\n
length = len(pic_content)\n
html_resp = html\n
html_resp += \"%d\\r\\n\\r\\n\" % (length)\n
print html_resp\n
html_resp += pic_content\n
print \"404 occur\"\n
html_resp = html404\n
while len(html_resp) & 0: \n
sent_cnt = conn.send(html_resp)\n
print \"sent:\", sent_cnt\n
html_resp = html_resp[sent_cnt:]\n
conn.close()\n\nif __name__ == \"__main__\":\n
agentd = agentD(pidfile=\"agentd.pid\", stdout=\"agentd.log\", stderr=\"agentd.log\")\n
agentd.run()实现了一个非常蹩脚的HTTP Server :-P上面守护进程的生成步骤中涉及到了孤儿进程:任何孤儿进程产生时都会立即为系统进程init自动接收为子进程,这一过程也被称为“收养”。但由于创建该进程的进程已不存在,所以仍应称之为“孤儿进程(Orphan Process)”。与之相关的一个概念就是 僵尸进程(Zombie Process)了。当子进程退出时, 父进程需要wait/waitpid系统调用来读取子进程的exit status, 然后子进程被系统回收。如果父进程没有wait的话, 子进程将变成一个\"僵尸进程\", 内核会释放这个子进程所有的资源,包括打开的文件占用的内存等。但在进程表中仍然有一个PCB, 记录进程号和退出状态等信息, 并导致进程号一直被占用, 而系统能使用的进程号数量是有限的(可以用ulimit查看相关限制), 如果产生大量僵尸进程的话, 将因为没有可用的进程号而导致系统不能产生新的进程。因此很多自带重启功能的服务实现就是用wait/waitpid实现的。waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。比如tornado中fork多进程就是这样, 监控子进程的运行状态, 当其意外退出时自动重启子进程。最后做个小广告,欢迎大家关注公共号,高品质运维开发,我们每周五晚上还会做线上公开课,加QQ群
报名即可,都是关于Linux、运维、Python和前端的相关内容运维开发交流QQ群: 欢迎大家关注公共号,高品质运维开发关于Reboot:专注于互联网运维开发分享、交流,让更多的运维工程师更加专注于自动化,为国内公有云开发、监控、运维贡献自己的力量。这里聚集着国内一线互联网工程师,乐于分享与交流 。发现文章不错的话请关注我们。Reboot于每周五开展免费技术沙龙分享时间:本周五(5月27日),21:00开始(明晚)方式:网络直播内容:主题:浅析Ceph主讲人:前360分布式攻城狮内容:解开Ceph神秘的面纱Ceph工作原理及流程Ceph 日常维护及常用操作参与请加分享群:","updated":"T10:47:30.000Z","canComment":false,"commentPermission":"anyone","commentCount":4,"likeCount":93,"state":"published","isLiked":false,"slug":"","isTitleImageFullScreen":false,"rating":"none","sourceUrl":"","publishedTime":"T18:47:30+08:00","links":{"comments":"/api/posts//comments"},"url":"/p/","titleImage":"/cfea012f53a7_r.jpg","summary":"","href":"/api/posts/","meta":{"previous":null,"next":null},"snapshotUrl":"","commentsCount":4,"likesCount":93},"":{"title":"面向工资编程","author":"auxten","content":"著作权归作者所有。转载请联系作者获得授权。经常看我专栏的朋友知道,我很少写跟编程无关的话题。很多人问过我一个问题,知道面向过程编程、面向对象编程,但你的“面向工资编程”是什么意思?\n其实说来也惭愧,这个称号本来是 (tony)用来黑我的。在他出任CEO之前,我们同为后端技术狗,每天都开心地写着C with class和Python,自然惺惺相惜什么都聊。\n突然有一天,我跟他说,哥被老谭调去做Android去了,去为公司做一款新的企业安全的产品,主要功能是为企业移动终端提供BYOD和MDM功能……blah、blah。大致过了小半年时间,产品做出来了,取名叫“360天机”。期间我和“力总”从RoR写到Java,从服务端写到手机端,从客服干到运维。后来,又从第一行代码写起创造出来了“360流量卫士”,各种磕磕碰碰在此不表。\n后来一次和tony一起和几个大神学长吃饭聊到编程语言(程序员聊天的羁绊),tony黑我说,只要给疼神工资,他啥都写,就是“面向工资编程”。\n后来我细细想来,tony说的也挺有道理:\n职业生涯里,我觉得对我影响巨大的一个人莫过于“雪糕”了。刚从百度到360的时候,我有点不适应,在百度每个人都有明确的模块,明确的代码要去编写,天天都很忙。但在360,自己开始带人了,开始显得有点不知所措。后来,跟雪糕的一次聊天,让我茅塞顿开,后来自己摸爬滚打了几年又有了一些自己的认识,给大家分享一下,希望对在职场上迷茫的朋友有所启发。\n谁将会升职加薪第一次在百度遇到“技术评审”的时候,我很好奇地问经理:“这么多人,到底谁会顺利的通过评审呢?”。经理没有正面回答我:“你看,咱们团队里,谁最应该被提拔呢?”。我恍然大明白:“当大家都觉得你该升职了,那你就几乎一定会升职加薪!当大家都觉得你是团队的顶梁柱,那你一定会成为Leader!”,这也许就是“众望所归”吧。\n面向工资编程刚工作的时候总觉得自己是在改变世界,而不是拿钱写代码。我相信很多对于技术有所追求的技术人员都或多或少有这种想法,也正是因为这种想法,让我们如饥似渴的学习各种新技术,每天都劲头十足的干着外行觉得很枯燥的事情。\n但直到后来自己开始带团队才发现一个有趣的现象,一些技术厉害的人很难“调用”。安排任务的时候,如果他觉得这件事没有技术含量,他就不愿意去做,或者不用心去做。\n跟很多技术管理人员交流时候发现,这种现象很普遍。这种想法也许也正是“自己是在改变世界,而不是拿钱写代码”的一个衍生品。这种行为对于一个程序员的发展是极为不利的,试想经理手下有两个能力差不多的程序员,一个任劳任怨,从不挑活,一个只干自己想做的事情,在团队中大家会觉得谁是“扛把子”?\n接触的各行各业的人多了,慢慢明白一个道理。其实,工程师跟其他各行各业的从业者没有什么区别,都是“拿人钱财,与人消灾”。既然你还在这个岗位,领了公司给的工资,有什么理由挑三拣四呢?所以,请“面向工资编程”。\n我是包工头这是雪糕当年跟我说的,好像是当年老谭跟雪糕说的。评价一个员工最好的词就是“靠谱”。人往高处走,大家负责的事情总会越来越多,需要做的事情越来越倾向于“无论你用什么办法,把这件事搞定”。\n这时候有些傻孩子可能会抱怨:“公司给我卖白菜的钱,凭什么让我操卖白粉的心!”。孩子,职场上,你需要证明有这个能力,然后组织才会给你相应的职位和待遇。\n什么,万一黑心老板不给呢?那么请记住这句话:“经历各种事情锻炼出来的能力,是别人拿不走的”,剩下的就自己琢磨吧。最后做个小广告,欢迎大家关注公共号,高品质运维开发,我们每周五晚上还会做线上公开课,加QQ群
报名即可,都是关于Linux、运维、Python和前端的相关内容运维开发交流QQ群: 欢迎大家关注公共号,高品质运维开发关于Reboot:专注于互联网运维开发分享、交流,让更多的运维工程师更加专注于自动化,为国内公有云开发、监控、运维贡献自己的力量。这里聚集着国内一线互联网工程师,乐于分享与交流 。发现文章不错的话请关注我们。著作权归作者所有。转载请联系作者获得授权。","updated":"T09:24:18.000Z","canComment":false,"commentPermission":"anyone","commentCount":40,"likeCount":268,"state":"published","isLiked":false,"slug":"","isTitleImageFullScreen":false,"rating":"none","sourceUrl":"","publishedTime":"T17:24:18+08:00","links":{"comments":"/api/posts//comments"},"url":"/p/","titleImage":"/425da73b960bd5c66bb086_r.jpg","summary":"","href":"/api/posts/","meta":{"previous":null,"next":null},"snapshotUrl":"","commentsCount":40,"likesCount":268},"":{"title":"中小公司员工统一用户认证方案(视频版)","author":"auxten","content":"前言前段时间发了一篇: 的技术贴,也是一篇实用性文章,很多程序猿都在关注,不少童鞋在后台询问后续内容是否出来。呼声很高的视频版终于出来啦,希望对大家有所帮助哦。视频(百度网盘下载高清视频:链接: 密码:ivdl )内容分享的主题:OpenLDAP 企业应用分享的内容:公司为什么需要统一用户认证?解决用户统一认证都要干哪些事?LDAP 都存了哪些员工信息?实现一个简单的用户登陆 APIOpenLDAP 安全OpenLDAP 公司应用架构图为什么需要统一用户认证?常遇到的问题:GitLab、Jira、Confluence ... 各种密码IT 遇到的问题:内网安全?公司一个 Wi-FI 密码大家都可以连接A 员工离职了一堆帐号我要挨个去删运维遇到的问题:VPN、Zabbix、Jenkins .... 各种密码运营遇到的问题:A 业务线,帐号xxx 密码xxxB 业务线,帐号xxx 密码xxx怎么去解决遇到的问题?LDAP 用户统一认证运维需要做什么?搭建一套完整的 LDAP 服务,给各个应用分配可以连接 LDAP 的账号配置 GitLab、Jira、Zabbix、Jenkins、VPN ...认证走 LDAP对外提供 API 给开发调用(可选)自己开发的运维平台也用 LDAP 认证开发机登陆(ftp、samba、ssh) ...开发需要做什么?开发人员开发的公司内部系统统一走 LDAP 认证主流语言PHP、Python、Java 都有 LDAP 库IT 需要做什么?Wi-FI 认证这块用到 FreeRADIUS,让 Radius 去走 LDAP 认证员工常用信息(手机号、邮箱、部门、IP地址...)全部录到 LDAP 中IT 统一维护,方便管理用户信息(办理员工入职、离职)LDAP组织数据的方式dn:每一个条目都有一个唯一的标识名(distinguished Name ,DN)例如:uid=woniu,ou=SRE,dc=51reboot,dc=com一个普通用户都要存哪些信息?ObjectClass 是什么?对象类是属性的集合,LDAP预想了很多人员组织机构中常见的对象,并将其封装成对象类。比如人员(person)含有姓(sn)、名(cn)、电话(telephoneNumber)、密码(userPassword)等属性,单位职工(organizationalPerson)是人员(person)的继承类方便用户查询信息:实现一个简单的用户登陆 API了解 LDAP 是怎么登陆?举个常用软件配置的例子 Gitlab知道原理之后,用 Python 实现一个简单的用户登陆API常用服务的配置 SSH了解 LDAP 是怎么登陆?LDAP 需要需创建一个账号给 gitlab 连接使用根据 uid 去查询用户的完整信息,类似于MySQL(select * frommysql.user where user='woniu')获取DN信息+密码,再去LDAP服务器认证,验证成功,用户就登录了查看 Gitlab 配置OpenLDAP 安全密码复杂度(8位大小写数字)密码错误次数锁定用户 (三次错误帐号锁定)密码有效期90天,提前7天邮件通知,超过时间强制修改密码提供重置密码和修改密码接口
开源:分布式LDAP 是以明文的格式通过网络来发送信息的,包括client访问ldap的密码使用TLS:(Transport Layer Security,传输层安全协议),用于两个应用程序之间提供保密性和数据完整性关掉匿名访问VPN (AnyConnect) + GoogleAuthenticatorOpenLDAP 在公司应用的整体架构图周五分享精彩预告:时间:06月17日 21:00主题:Python 实现运维自动化平台主讲人:运维男神 ——刘天斯分享请加:Reboot 周五分享群 最后做个小广告,欢迎大家关注公共号,高品质运维开发,我们每周五晚上还会做线上公开课,加QQ群
报名即可,都是关于Linux、运维、Python和前端的相关内容运维开发交流QQ群: 欢迎大家关注公共号,高品质运维开发关于Reboot:专注于互联网运维开发分享、交流,让更多的运维工程师更加专注于自动化,为国内公有云开发、监控、运维贡献自己的力量。这里聚集着国内一线互联网工程师,乐于分享与交流 。发现文章不错的话请关注我们。","updated":"T07:56:46.000Z","canComment":false,"commentPermission":"anyone","commentCount":16,"likeCount":151,"state":"published","isLiked":false,"slug":"","isTitleImageFullScreen":false,"rating":"none","sourceUrl":"","publishedTime":"T15:56:46+08:00","links":{"comments":"/api/posts//comments"},"url":"/p/","titleImage":"/f3e5056aacf26d0e836ccb07_r.png","summary":"","href":"/api/posts/","meta":{"previous":null,"next":null},"snapshotUrl":"","commentsCount":16,"likesCount":151},"":{"title":"技术分享丨如何基于Python构建一个可扩展的运维自动化平台","author":"xin-zhu-84-58","content":"嘉宾简介刘天斯从事互联网运维工作已13年,目前就职于腾讯-互动娱乐部,负责游戏大数据的运营,曾就职于天涯社区,担任首席架构师/系统管理员。热衷开源技术的研究,包括系统架构、运维开发、负载均衡、缓存技术、数据库、NOSQL、分布式存储、消息中间件、大数据及云计算、Mesos、Docker、DevOps等领域。擅长大规模集群的运维工作,尤其在自动化运维方面有着非常丰富的经验。同时热衷于互联网前沿技术的研究,活跃在国内社区、业界技术大会,充当一名开源技术的传播与分享者。导言今天受 Reboot 邀约与大家聊聊运维自动化的议题,与大家一起探讨如何基于Python构建一个可扩展的运维自动化平台,也希望能与大家一起交流,共同成长。此次分享将通过平台具备功能、架构设计、模块定制、安全审计、C/S结构的实现等几个方面内容来展开。为什么选择Python?几点优势:默认安装且跨平台、可读性好且开发效率高、丰富的第三方库(开发框架、各类API、科学计算、GUI等)、社区活跃&众多开发者。Python在腾讯的现状,根据去年内部提交组件语言统计,除去2、3、4前端技术,Python在高级编程语言中排第3位。应用在系统运维、业务逻辑、运营平台、测试工具、数据挖掘等领域,腾讯大名鼎鼎的“蓝鲸”运维PAAS平台就是基于Python语言来构建。一、平台介绍OMServer 一个集中式的Linux集群管理(基础)平台(《Python 技术与最佳实践》书籍实践案例),具备业务集群管理、实时安全审计、功能模块定制、数据加密传输、支持主流Python组件、使用简单且体验好等特点,源码托管地址:/yorkoliu/pyauto,读者可以根据企业的需求定制修改及发布。1、平台截图:2、平台采用到的第三方库:Django - 一个开放源代码的Web应用框架,由Python写成,采用了MVC的软件设计模式;rpyc - 一个 Python 实现的RPC和分布式计算的工具。支持同步和异步操作、回调等;saltstack 、ansible 、func - 基本Python开发的自动化配置管理与流程控制组件;Mysql - 是一个非常流行的关系型数据库管理系统。二、平台架构设计1、
OMServer架构图大家对这个架构应该不会感到陌生,三层结构也是目前主流的运营平台架构2、
架构说明OMServer平台为三层架构,分别为WEB交互层、分布式计算层、集群管理服务层。1)、第一层:即为WEB交互层,典型的B/S架构,以供管理员操作的交互平台,也是OMServer的核心,基于Django开发;2)、第二层:分布式计算层,提供与主控端的连接通道,采用的是rpyc传输协议,协议操作流程:前端模块参数-&加密传输-&任务执行-&返回结果集-&解密输出。3)、第三层:集群管理服务层,整合Python主流的远程操作组件(支持Saltstack、Anaible、Func),对被控端(业务服务器集群)进行管理,其中主控端可以根据不同IDC环境,采用多地多点的管理方式,可提升冗余度及执行效率。主控端操作模块以不同Python文件加以区分,便于维护,可灵活定制操作逻辑及横向扩展等特点。3、
平台架构优势1)管理端多机支持,可按不同IDC划分;2)安全性高,加密传输、定义私有通讯规范(TCP);3)支持多种管理客户端接入(WEB、桌面、移动);4)调用Python组件的高级特性(Playbook、State);5)功能扩展性能力强,模块定制化。4、架构操作流程上图将三个层次的交互流程进行串连,可以清晰了解OMServer架构的操作流程,结束了传统式直连APP Server的操作,更加规范我们的操作事件,一定程度可以避误一些潜在的误操作。5、整合远程操作Python组件分别两个步骤:1、提前配置主控端与被控端的信任关系,一般为证书或SSH 认证;2、通过OMServer主控端封装好的任务模块与API接口,实现定制化的任务下发及执行。三、平台模块定制1、任务模块定制的思路1)任务模块 – 即为一个“操作事件”为颗粒的任务,如重载配置、部署缓存服务、停止Nginx服务等原子操作;2)添加模块的步骤:-
定义任务模块“输入参数”,采用HTML Form元素,可以为输入、下拉、单复选框等元素;编写后台模块代码,其中执行部分由Saltstack或Ansible的Client_API来实现;
- 任务模块核心代码,只需要5行代码就可以实现一个SHELL脚本下发、执行的功能。3)运行模块的步骤 - 选择任务模块 & 操作对象 -& 指定输入参数 -& 运行 -& 返回执行结果。2、当我们的平台已经具备可定制、扩展操作的能力,运维的核心工作就聚焦以下几点:1)平台功能改进、升级,需要具备DevOps能力;2)根据业务运营需求,做任务功能模块的编写的工作;3)日常工作梳理(标准、流程化建设),更好将原子操作串成流程。4)系统、业务的调优,服务业务。四、安全审计的实现1、
安全审计技术架构2、Agent上报实现原理实现原理非常简单,通过修改Linux系统环境配置文件/etc/profile,定义history事件相关环境变量,捕捉所有Linux登录用户会话中的操作事件及指令,实时通过OMAudit_agent.py中的HTTP GET CGI向数据库写操作事件流水。管理前台页面通过定时刷新,获取最新的操作事件。五、C/S结构的实现1、
OManager桌面版截图2、OManager桌面版架构桌面版OManager基于Wxpython + XRC构建,为两层结构,一层为桌面客户端,另一层为集群管理端,同时兼容OMServer管理端,通讯依然采用rpyc协议,与OMServer有以下几点区别:3、后续优化1)整合ansible或saltstack高级功能,如ansibleplaybook;2)将多个任务模块打包成模板对列,实现原子操作与运维变更流程的结合;3)引用任务调度Celery,支持更大并发;4)任务对列支持暂停、中止、重运行功能,实现操作可控。5)提供与CMDB访问对接,通用性更强。 Q&AQ1:个人可以完成运维自动化平台吗,需要哪些技术?当然可以,腾讯内部对运维人员都有一个要求,就是要具备开发能力。Python简单,容易入手,强烈推荐。Q2:分享中有提到 CS 架构中安全性高,请问具体高在哪些方面,是什么原因呢?一般CS客户端部署在管理员电脑,通过私有网络、协议与主控端效互,B/S部署在节点与业务集群同区域,不一样同网段,另外黑客对WEB层的攻击远高于桌面客户端,网络隔离在这时候显得尤为重要了。Q3:自行研发tglog对于海量日志传输是否主要走的udp协议?如果是走的udp协议,怎么去解决一些数据包传输中数据乱序以及数据反序列化问题,或者做了哪些协议层面的优化?是的,主要走的是UDP协议。tglog同时也是一套数据日志的规范,约束开发人员打日志的标准。目前未碰到数据乱序以及数据反序列化问题,以前面临一个比较大的问题是丢包情况,尤其在流量高峰期时段更为明显。后面在内核、IO优化得到缓解,但无法规避,所以我们对比较重要的日志采用TCP传输。比如玩家消费流水。Q4:规范化、标准化遇到最大问题是什么?我们遇到就是无法行政干涉开发如何写代码?有什么好的方式去引导规范?尤其是开发有很繁重的开发任务.A: 这已经不是运维层面推动的事情,必须升级到运维及开发的上层领导,开发任务繁重不是理由,上线后出问题一样得不偿失,提前抛出风险,让开发人员认真做好上线前的评估。Q5:运维管理系统安全性这块有什么好的思路?1、网络的隔离,避免直接暴露在公网;2、办公电脑需要有一套标准的日常安全规范,尤其是运维办公机;3、平台编码人员需要有较好的安全意识;4、多关注业界安全、漏洞事件。参与方式1、想要参加“技术沙龙-周五课堂”的小伙伴请加群:Reboot 周五分享群 2、关注Reboot微信公众号课程消息:Python实战第10期,于7月2日开班!本期课程将增加多线程、多进程等内容!要参加的童鞋,现在开始报名啦!咨询 QQ: 课程大纲:Python实战班:运维自动化班:","updated":"T16:07:19.000Z","canComment":false,"commentPermission":"anyone","commentCount":3,"likeCount":65,"state":"published","isLiked":false,"slug":"","isTitleImageFullScreen":false,"rating":"none","sourceUrl":"","publishedTime":"T00:07:19+08:00","links":{"comments":"/api/posts//comments"},"url":"/p/","titleImage":"/49c1e8ed434c84e19e4a_r.png","summary":"","href":"/api/posts/","meta":{"previous":null,"next":null},"snapshotUrl":"","commentsCount":3,"likesCount":65},"":{"title":"高德API+Python解决租房问题","author":"sw2016","content":"项目简介:编写Python脚本爬取某租房网站的房源信息,利用高德的 js API 在地图上标出房源地点,划出距离工作地点1小时内可到达的范围,附上公交路径规划功能查看不同路径的用时。项目由发布在,完整教程及在线练习地址:,可以直接在教程中下载代码使用demo。一、介绍1. 背景项目来自一段租房血泪史(夸张):事情是这样的,笔者是接着念大四准备考研,而室友是应届毕业在找工作,说白了就是都没有钱,于是打算合租。因为穷所以不可能找有门店的的中介,只能看看赶集、58、和一些租房APP。期间需要考虑两个人的通勤范围来选地段,由于对交通的不熟悉,只有选择自己附近的较贵的地段,花了很多时间阅览赶集或者58里的个人房源信息,然而个人房源信息中仍充斥着大量中介,抱着一点希望打了几个电话,得到的回答都是这个价位根本租不到,再高点也租不到(大都与发布的房源信息不符)。最后终于还是在宿舍关闭前一个星期租到一个性价比还可以的隔断。毕竟隔断还是不方便的,所以打算在室友找到工作后换一个新地方,于是就有了这个租房脚本和课程。相信也有不少的应届毕业生可能会遭遇同样的境况,希望这门课能真的帮到大家,也许不光是在租房子方面。总结一下租房难的症结:没钱。小中介发布的价位一般都是假的,会浪费你很多时间。对交通路线不熟悉以致于选择面窄。如果是多人,得同时考虑多人的通勤时间。本课程将解决的问题:学习了技术,增长了知识,就能找到好工作,找到好工作就能有钱。这次选的房源信息来自58的品牌公寓馆,所以没有那种小中介,价位就我和我室友来说可以接受。其实可以做个分类器过滤赶集上的中介来找低价个人房源的,有需要的同学可以试一下。通勤范围在地图上圈出,解决了对交通路线不熟悉的问题本课程是单人版的,但代码中只要删掉一个语句就能当多人用了(但是路径规划的功能是只能给一个人用)。如果是直接拿来多人用的话,还是开多个页面比较好。最终效果图如下:由于没做前端兼容,导致右上角崩了。自用的小工具其实也不用整多好看,效率第一。如图,划出来的大片蓝色色块就是距离工作地点一小时车程内的区域。蓝色的标记就是房源,点击后会自动给出路径规划和房源地址。红色标记(不是\"终\")是工作地点,在图里被挡住了。工作地点的输入框有自动补完的功能,也是很方便的。至于房源文件我们会通过编写Python脚本在抓取房源信息后生成。2. 知识点本课程项目完成过程中,我们将学习:requests、BeautifulSoup、csv 等库的简单使用高德地图 Javascript API 的使用二、实验环境打开终端,进入 Code 目录,创建 rent_proj 文件夹, 并将其作为我们的工作目录。$ cd Code\n$ mkdir rent_proj && cd rent_proj\n安装需要的库:$ sudo apt-get install python-bs4\n三、实验原理实验中会用到三个文件:crawl.py,rent.csv与index.html,其中rent.csv由crawl.py生成,是房源文件。crawl.py是一个非常简单的爬取网页的脚本。index.html是最重要的显示地图的部分。实现的流程大致如下:我为什么不把js代码和css代码从index.html中分出来呢,写脚本怎么顺手怎么来就好。四、效果演示首先选择工作地点,划出了一小时内的通勤范围:北京堵车太猖狂,可能还是地铁保险:导入房源文件后:选择一处房源,会自动帮你规划路径:选中房源地址跳转到目标页面:本项目的详细教程、完整代码及demo测试,可在中查看并在线完成,更多Python经典项目:","updated":"T07:44:01.000Z","canComment":false,"commentPermission":"anyone","commentCount":74,"likeCount":1274,"state":"published","isLiked":false,"slug":"","isTitleImageFullScreen":false,"rating":"none","sourceUrl":"","publishedTime":"T15:44:01+08:00","links":{"comments":"/api/posts//comments"},"url":"/p/","titleImage":"/80edae0e5bfc4f_r.png","summary":"","href":"/api/posts/","meta":{"previous":null,"next":null},"snapshotUrl":"","commentsCount":74,"likesCount":1274},"":{"title":"程序员面试所需的软技能","author":"woniuppp","content":"写在前面:本文建立在代码基础过硬,想一起研究一下面试中锦上添花的一些技能,注意不是雪中送炭,基础不好的,还是看看之前的文章,好好学学Python再来看吧最初想写这篇文章,是因为平时上课的时候也会见缝插针的讲一些面试题,但是大家给我关于面试的反馈,通常不是某个笔试题不会做,而是一些开放性的问题不知道怎么回答。特别是一些面试到了三面的时候,基本都不会问太多技术问题,这样普遍不善言辞的程序员们很是惆怅,于是我决定分享一下自己当程序员这几年关于面试的一些软技能。是的,你没看错,本文全程无代码。本文将围绕几个问题来逐个展开面试准备自我营销关于终面:一些扯蛋问题的心得如何谈薪酬文章略长,快上车,慢慢看!面试准备作为IT从业人员,跳槽是职业生涯中很重要的一个步骤,这方面我就不讲太细了,毕竟有很多讲职业生涯选择的文章。我只提醒一点,自己的职业生涯,还是要自己好好规划,想好为什么跳槽就可以了。有了换工作的想法之后,第一件要做的事就是做简历。大型超市为了卖掉更多的洗头膏,都会精心设计一个促销区域,但是我们找一个年薪几十万的工作,却不愿意花心思好好整一下简历。我说的意思不是请专业人员把简历做的酷炫,而是要让简历突出重点,写一份让别的程序员能看懂的简历就OK了。简历控制在一张A4纸以内,最好不要超过两张原因很简单,因为HR和面试官平时都挺忙的,没有那么多时间看简历,最多扫一眼第一页就不错了,所以很多面试官会要求你自我介绍,其实就是他们没看简历~~技能只写最重要的会Word,Excel 啥的就不要写啦,只是用过 Linux 也不要写啦,大学当过什么学生干部啥的也不要写。如果面的职位是Python,以前搞过 asp.net 也不要写啦写点和职位相关,直接能让面试官高潮的技能,比如面运维开发时,就写自己实现过CMDB,上线,工单系统,Django,Flask用的很熟练什么。面前端时,就写自己看过Jquery,angular,vuejs源码啥的,直接命中面试官内心深处的渴望:卧槽,这就是我要的人!展示自己的潜力其实我觉得,让面试官觉得你有潜力的方法最好的方法,就是搞一个博客和Github,记录自己平时的学习和代码。面试官就会觉得你善于总结,对编程有强烈的兴趣,即使你现在技术有些缺陷,也是可以慢慢培养的。这个就属于自我营销,后面会谈及。自我营销想象一个面试场景,你做完自我介绍后,面试官突然饶有兴致的对你说:原来你就是蜗牛啊,我之前看过你的博客,你xx文章里面总结的xx真是不错啊,你应该就可以预计到这场面试的结果,很大概率不需要太多技术问题,就可以直接谈薪资了,而且这是一个真实的故事。打造自己的品牌博客程序员也需要打造自己的品牌,营销自己。最简单的,就是建立自己的个人博客,大概步骤有这么几个吧,以PC大大的知乎专栏举例明确要表达的品牌信息PC大大的专栏,都集中在网络编程方面挑选细分市场受众就是写给运维开发看创建品牌的口号和标示现在运维圈,提起面向工资编程,都会想到这个专栏,并且这个口号实在是太懂程序员了,俗话说得好, talk is cheap, show me the money内容为王花心思总结一下自己的心得,这个专栏里关于网络编程和操作系统的文章,含金量还是大大的善用社交网络直接在知乎里面回答问题,捕获众多粉丝当然还有很多其他博客平台,比如博客园,51CTO,Github都可以成为你自己积攒个人品牌的好平台我觉得现在PC大大换工作,简历里直接贴个专栏地址,比说什么都有效吧b、注册一个 github账号把自己的日常代码都放上去,即使关注度不够,HR和面试官也会看到你一个个的提交记录,会觉得你是一个很勤奋的人c、演讲和大会分享演讲是进行自我营销的最有效方法之一,虽然扩散速度不及其他媒介,但是真的面对受众,面对面的侃侃而谈,才是最能打动他们的方式,也是你锻炼面试能力的一个最好途径大会演讲如果有机会去各种技术大会作分享,千万把握好机会,这是创建自己品牌非常好的机会,说不定下面就会有你以后面试官听你分享分享和培训如果和我一样,没有机会去大会讲,可以在公司内部主动推动一些小分享和培训会,锻炼自己的演讲能力d、个人品牌终极方案—著书写书对个人品牌效应无需多说,我们对很多技术大神,比如刘天斯大神,印象就是《Python自动化运维:技术与实践》的作者。肖力大神,就是《深度实践KVM》的作者。这两位大神如果出去面试,指不定面试官还会求一本签名书。当然写书需要太多知识和时间的沉淀。我希望以后也可以出本书,但是现在还是老老实实写博客才靠谱。关于终面:一些扯蛋问题的心得其实到了终面,基本都是部门负责人了,你已经过五关斩六将的过了好几轮技术面,所以老大基本就不会问你职位相关的技术问题啦。老大所关注的,基本就是你这个人怎么样,有没有培养的价值,所以大致会问你这几个问题(比如你面的是Python的职位)你为什么要换工作老大问你这个问题,就是想评估一下如果你入职之后,能待多久,公司团队能不能把你融进来。我觉得这个问题,程序员们就不要太纠结于技巧了,直接老老实实从下面俩原因选一个或都讲,坦诚相待就OK了:钱不够,薪资没达到期望值这个大家不要避讳,HR和面试官会觉得这个原因是OK的觉得现在的工作在浪费时间,没有成就感,想找一个更牛的团队,实现自己的价值表达自己技术和职业上的追求,而不是混日子养老注意一定不要说是因为和领导闹得不愉快,或者领导傻逼这种话,面试官要是听到这种话,内心独白就是:老子要是把你招进来,以后你背后是不是也会骂我,那赶紧滚犊子吧。然后面带微笑的说,今天的面试就先到这了,balabala……回答完这个问题之后,最好在表达一下自己心中的技术团队的氛围,常用词汇有,开放,对事不对人,敢于尝试新技术,等等你平时业余时间都做什么其实这个问题我最有发言权,因为我有很多面试都是基本只聊这个就聊到了offer一个人的业余时间用来做什么,就决定了他的未来
马云老大问这个问题,其实目的就是想看你到底是个什么样的人,千万不要回答没啥爱好,回家就看看电视剧睡觉啥的,显得太不上进。基本来说,我常用的回答,业余时间喜欢运动一下,看看书,打打游戏什么的,下面老大一定会会问,喜欢什么运动啊,看什么书啊,都玩什么游戏啊之类的,我分别讲一下这几个,也仅供大家参考:喜欢什么运动其实回答一下自己确实喜欢的运动就好,最好是团体或者比较流行的,比如回答踢足球,乒乓球,羽毛球都是很不错的。互联网公司还是非常喜欢组织这些球类比赛,你会这些的话,大家可以一起玩耍,面试官当然愿意啦,或者你看面试官穿着冲锋衣,说自己喜欢户外露营徒步,都是不错的,显示自己很阳光,并不是特别闷骚然后后面就可以展开聊啦,你自己平时注意积累一下相关的行话,比如喜欢踢球,就找一个死忠的球队,并且用专属名称,比如法国球迷,就说自己喜欢高卢雄鸡,英国就是三狮军团,荷兰就是橙衣军团,德国就是德意志战车,并且选两个喜欢的球员,描述语就用球风硬朗、意志顽强,脚法精准,身体对抗多,全场跑动多等等装逼词汇就差不多了喜欢看什么书上个问题其实无关痛痒,这个问题才是老大最感兴趣的,平时看书的时候注意自己对这个问题答案的丰富和积累,比如回答就看点技术书啊,除了技术书就看点畅销书和名著,偶尔也看点玄幻小说啥的就还不错,这里面试官一定会和你聊具体你看过的书,所以对自己列举出来的书,一定要有自己的观点。技术书就可以列举基本耳熟能详的,老大也不会多问,玄幻小说也没啥可聊的,总不能和你聊凡人修仙传吧,所以重点就是畅销书和名著了,注意,一定要有自己的观点,奇葩无所谓,要让面试官觉得你是有独立思考能力的人就可以了畅销书这个就说几本看过有点名气的就行,比如浪潮之巅,人类简史,从0到1都不错,重点聊点读完的理解,这个就没啥太多技巧了,平时看几本备用吧,比如关于浪潮之巅,你可以借用硅谷之谜里面关于机械论和三论的总结,非常精彩关于名著这个其实才是扯蛋的重点区域,下面几个段子是我经常用的,分享给大家,立等可取,任君享用:1.三国演义对赤壁那段印象很深刻,特别是赤壁之战之后,关羽把曹操给放走了,当时还倍感可惜,关二爷就应该手起刀落balabala,后面再读,就觉得诸葛亮真是牛逼啊,其实是故意放走曹操的,因为当时刘备的势力还不能和孙权对抗,如果宰了曹操,势必把大好天下拱手让与孙权,是自寻死路,所以曹操肯定不能死如果直接装作没有抓到曹操,东吴和天下人都会觉得刘备这边能力太差了,没什么能力,对成就霸业不利,所以必须要抓住曹操但是如果抓住直接放走曹操,和孙权的结盟关系势必破裂,对当时还弱小的刘备势力也是毁灭性打击,所以算准了曹操对关羽有恩,关二爷重义气,定会放走曹操,所以才把关二爷放在了最可能宰掉曹操的华容道,事后东吴来问罪,就装作要斩关羽,最后刘备出来求情,借坡下驴,赦免了关羽,所以诸葛亮既向天下人展示了刘备的能力,也没有让东吴一家独大,又没有让联盟关系破裂,还顺便成就了关二爷的忠义之名,真是太屌了。2.西游记关于真假美猴王,孙悟空真是太鸡贼了,唐僧老是念紧箍咒,自己造了一个一模一样的猴子,装作是六耳猕猴尥蹶子不干了,一直到如来亲口答应安心取经,以后一定可以成佛才作罢,就像现在的老板承诺给股权,好好干,公司上市了一定给你XXX一样。类似的例子还有很多很多,随便讲一个就行。3.梁山伯与祝英台其实梁山伯是个同性恋,因为梁山伯一直都不知道祝英台是女的,所以他喜欢的是男版的祝英台,最后发现祝英台是女的,内心无法接受,悲愤不已,自杀殉情(这个观点是一次听江南春演讲听到的,不是我侮辱传统文化,勿喷)。类似的例子还有很多,平时注意积累几个就行,比如武侠什么的都是可以聊的,你可以用慕容复打不过乔峰,来类比编程内力和编程招式的区别,总结编程需要多修炼内力等等,大家自己发挥吧,毕竟面试官也挺累的,给他们一点新奇的观点,也能让他们对你提起兴趣。关于游戏游戏就说自己会的就行啦,比如dota,LOL,三国杀,狼人杀神马的都可以哇,重点是能聊上就可以啦。除了xx,你会其他编程语言吗这个就是看眼界的问题了,建议大家都能掌握一点其他的来应对这个问题,比如我基本都是面前端的职位,到了终面,就可以说自己也会Python和运维开发,然后就说一下自己对于运维开发,Python的理解,其实也不会聊特别具体的技术问题,老大主要看你眼界够不够宽。你还有什么问题吗最好不要回答没啥问题了,一定要问几个,显得自己对这个工作是特别渴望的,比如下面几个:咱们部门具体采用的技术方案是什么我如果能来,是一个什么角色公司未来两到三年对技术部门的规划是什么我今天面试的结果大概是怎样的,有哪些需要继续提升的如何谈薪酬很多程序员,包括很久之前的我,都根本不会谈薪酬,或者谈一次就放弃,别人给多少就是多少。薪酬谈判其实还是蛮重要的,不仅仅是多的那些钱,更重要的因为薪酬谈判中你如何评价自己和谈判能力,会影响公司对你的看法。一旦成为公司的一员,其实你很难改变别人的第一印象,涨薪也是按照百分比,仔细的谈一下薪酬,可以让未来的雇主觉得你是一个很有价值的员工,就像我当年进百度,傻不呵呵的说了一句对薪资没啥要求,结果应该就是最低的工资,囧。其实薪酬谈判是受你自己的声望和能力影响的,想一下你如果你的Github主页有2000个星星,谈判的时候的主动权会非常大,所以薪酬谈判很大一部分因素是日常的积累,就像前面说的自我营销。获得面试机会的类型你获取工作方式的不同,也决定的你薪酬谈判时候的地位,通常来说是 公司主动找到你&内推&猎头&自己海投,所以大家尽量找关系内推。如果有一天你的博客下面收到以下面试邀请,那你的谈判主动权会大大提高,所以还是注意日常积累吧不要先出价谈判一个重要法则,就是先出价的会比较处于劣势,因为你没法加价了,却给了对方砍价的空间,但是要一个过于高的价格,又会让雇主直接放弃,我的策略是,先找到自己的定位,然后再谈判找准自己的定位比如你特别想去A公司,你现在公司是10K,先找几个BCDE公司练练手,薪酬谈判的时候直接要高价,比如20K如果对方想也没想就拒绝了,说明自己现在还不够格,下次面试要15试试如果对方犹豫或者答应了,下次面试你就可以要25K 以此类推目的就是找准市场给自己的定价,心里有一个谱。具体谈判面试官和HR一定会问你,你的薪资要求.这个时候最好的回答就是拒绝回答,面试申请单要求写期望薪资,可以写根据薪酬体系面议,面试官问你,也给出相同的答复,如果再问,可以用几个问题缓解一下,比如给出预期之前,我愿意更了解一下贵公司和我的工作内容关于这个职位,你们一定有一个具体的预算,我可以告诉你们这个预算是不是符合我心理预期我现在没法给出一个具体的数字,如果一定要的话,大概是XX到XX(就必须说出一个区间了)我手里已经有月薪15K的offer了,诸如此类,提高自己谈判的地位最后的建议面试是个技术活,一定要弄清楚自己值多少钱,并且平时注意自己的积累,不仅仅是技术,各种软技能的修炼也是非常重要的。以上都是我的一点心得,这些内容在上课的时候也会给学员们讲到,现在写出来分享给大家,能对你有帮助那是最好的了。祝大家都能拿到梦寐以求的offer。最后发个小广告,Reboot运维开发技术交流QQ群","updated":"T03:16:32.000Z","canComment":false,"commentPermission":"anyone","commentCount":38,"likeCount":252,"state":"published","isLiked":false,"slug":"","isTitleImageFullScreen":false,"rating":"none","sourceUrl":"","publishedTime":"T11:16:32+08:00","links":{"comments":"/api/posts//comments"},"url":"/p/","titleImage":"/v2-778a84fcd1fea3e5e050dd_r.jpg","summary":"","href":"/api/posts/","meta":{"previous":null,"next":null},"snapshotUrl":"","commentsCount":38,"likesCount":252},"":{"title":"网络编程(九):Python裸写异步非阻塞网络框架","author":"auxten","content":"裸写的意思就是不用任何第三方库,这样有助于网络编程入门的同学了解其中的奥秘。相关的前置的网络编程的知识参见: 好了,直接上代码(之前的代码是没有太多注释的感谢 给代码加了详尽的注释):
# 从之前写好的守护进程类中导入Daemon\nfrom daemon import Daemon\nimport socket\nimport select\nimport time\n# 导入pdb,即Python debug模块,方便调试\nimport pdb\n\n# 设定这个变量,可以控制本文件在被import *\n# 的时候导入的变量、函数和类的范围\n__all__ = [\"nbNet\"]\n#DEBUG = True\n\n# 这个文件的内容会在后面详述\nfrom nbNetUtils import *\n\n# 我们住程序的conn_state的类原型\n\nclass STATE:\n\n
def __init__(self):\n
self.state = \"accept\"
# 初始状态\n
self.have_read = 0\n
# 我们的程序在开始的时候总是要读取10个字节的头\n
self.need_read = 5\n
self.have_write = 0\n
self.need_write = 0\n\n
# 读写缓冲区\n
self.buff_read = \"\"\n
self.buff_write = \"\"\n
# 用来后续存放sock对象\n
self.sock_obj = \"\"\n\n
def printState(self):\n
debug输出函数\n
if DEBUG:\n
dbgPrint('\\n - current state of fd: %d' % self.sock_obj.fileno())\n
dbgPrint(\" - - state: %s\" % self.state)\n
dbgPrint(\" - - have_read: %s\" % self.have_read)\n
dbgPrint(\" - - need_read: %s\" % self.need_read)\n
dbgPrint(\" - - have_write: %s\" % self.have_write)\n
dbgPrint(\" - - need_write: %s\" % self.need_write)\n
dbgPrint(\" - - buff_write: %s\" % self.buff_write)\n
dbgPrint(\" - - buff_read:
%s\" % self.buff_read)\n
dbgPrint(\" - - sock_obj:
%s\" % self.sock_obj)\n\n\nclass nbNetBase:\n
non-blocking Net类,首先我们设定了一套通信的协议,以10个byte的\n
ASCII码数字的头来表示,后续数据的长度,例如:\n
hello world\\n\n
这样做的好处在于,我们可以很容易的解析消息的结束位置。\n
并且能够在这套框架下进行任何数据的传输,包括各种二进制数据,而不需要转义。\n
def setFd(self, sock):\n
\"\"\"把sock放进全局的conn_state字典里\"\"\"\n
dbgPrint(\"\\n -- setFd start!\")\n
tmp_state = STATE()\n
tmp_state.sock_obj = sock\n
self.conn_state[sock.fileno()] = tmp_state\n
self.conn_state[sock.fileno()].printState()\n
dbgPrint(\"\\n -- setFd end!\")\n\n
def accept(self, fd):\n
\"\"\"在fd上进行accept,并且把socket设置成非阻塞模式\"\"\"\n
dbgPrint(\"\\n -- accept start!\")\n
sock_state = self.conn_state[fd]\n
sock = sock_state.sock_obj\n
conn, addr = sock.accept()\n
# 把socket设置成非阻塞模式\n
conn.setblocking(0)\n
return conn\n\n
def close(self, fd):\n
\"\"\"关闭fd,从epoll中取消关注,清理conn_state里相关的数据\"\"\"\n
# cancel of listen to event\n
sock = self.conn_state[fd].sock_obj\n
sock.close()\n
dbgPrint(\"Close fd: %s abnormal\" % fd)\n
finally:\n
self.epoll_sock.unregister(fd)\n
self.conn_state.pop(fd)\n\n
def read(self, fd):\n
读取fd中的数据(非阻塞模式)\n
并且设置各个计数器的数值,以供后续处理\n
返回值是个字符串,表示下一步需要进行的处理,如:\n
“readcontent”、“process”、“readmore”\n
# pdb.set_trace()\n
# 从conn_state字典中取出连接\n
sock_state = self.conn_state[fd]\n
conn = sock_state.sock_obj\n
if sock_state.need_read &= 0:\n
raise socket.error\n\n
# 进行一次非阻塞的读取\n
one_read = conn.recv(sock_state.need_read)\n
dbgPrint(\"\\tread func fd: %d, one_read: %s, need_read: %d\" %\n
(fd, one_read, sock_state.need_read))\n\n
# 如果什么都没有读到,那应该是socket出错了\n
if len(one_read) == 0:\n
raise socket.error\n
# 将读到的数据放入buff_read,\n
# 设定have_read(已经从socket中读取的数量)\n
# 设定need_read(还需从socket中要读取的数量)\n
sock_state.buff_read += one_read\n
sock_state.have_read += len(one_read)\n
sock_state.need_read -= len(one_read)\n
sock_state.printState()\n\n
# 如果已经读取的数据是10个byte,那么说明数据的10字节头已经读取完毕,\n
# 我们可以解析判断后续的数据的长度了\n
if sock_state.have_read == 5:\n
# 由于是ASCII的数据头,我们需要用int()将它转化成数字\n
header_said_need_read = int(sock_state.buff_read)\n
if header_said_need_read &= 0:\n
raise socket.error\n
sock_state.need_read += header_said_need_read\n
sock_state.buff_read = ''\n\n
# 为了方便大家理解,这里打印一些debug信息\n
sock_state.printState()\n
return \"readcontent\"\n
elif sock_state.need_read == 0:\n
# 所有数据已经读取完毕,转入业务逻辑处理“process”\n
return \"process\"\n
# 出去上述的所有情况,剩下的情况就是还需要读取更多的数据\n
return \"readmore\"\n
except (socket.error, ValueError), msg:\n
# 进行一些异常处理\n
# errno等于11,即“EAGAIN”。是表示,还可以尝试进行一次读取\n
if msg.errno == 11:\n
dbgPrint(\"11 \" + msg)\n
return \"retry\"\n
# 除去上述的特殊情况,发生了任何错误,不要挣扎,直接把socket关闭\n
return 'closing'\n\n
def write(self, fd):\n
非阻塞的写数据到socket中,返回值的涵义和上述的read一致\n
# 还是取出fd对应的sock_state结构体\n
sock_state = self.conn_state[fd]\n
conn = sock_state.sock_obj\n
last_have_send = sock_state.have_write\n
# 非阻塞的发送数据,这里send的返回值是已经成功发送的数据量\n
have_send = conn.send(sock_state.buff_write[last_have_send:])\n
sock_state.have_write += have_send\n
sock_state.need_write -= have_send\n
if sock_state.need_write == 0 and sock_state.have_write != 0:\n
# 如果已经全部发送成功,返回“writecomplete”\n
sock_state.printState()\n
dbgPrint('\\n write data completed!')\n
return \"writecomplete\"\n
return \"writemore\"\n
except socket.error, msg:\n
# 发生错误,直接关闭socket\n
return \"closing\"\n\n
def run(self):\n
这个函数是装个状态机的主循环所在\n
while True:\n\n
# 这部分就是我们上面多次提到的epoll\n
# poll()返回的epoll_list就是有事件发生的fd的list\n
# 需要在循环中按照event的类型分别处理,一般分为以下几种类型\n
EPOLLIN :表示对应的文件描述符可以读;\n
EPOLLOUT:表示对应的文件描述符可以写;\n
EPOLLPRI:表示对应的文件描述符有紧急的数据可读;一般不需要特殊处理\n
EPOLLERR:表示对应的文件描述符发生错误;后面这两种需要关闭socket\n
EPOLLHUP:表示对应的文件描述符被挂断;\n
epoll_list = self.epoll_sock.poll()\n
for fd, events in epoll_list:\n
sock_state = self.conn_state[fd]\n
if select.EPOLLHUP & events:\n
dbgPrint(\"EPOLLHUP\")\n
sock_state.state = \"closing\"\n
elif select.EPOLLERR & events:\n
dbgPrint(\"EPOLLERR\")\n
sock_state.state = \"closing\"\n
# 调用状态机\n
self.state_machine(fd)\n\n
def state_machine(self, fd):\n
这里的逻辑十分的简单:“按照不同fd的state,调用不同的函数即可”\n
具体的对应表见nbNet的__init__()\n
sock_state = self.conn_state[fd]\n
self.sm[sock_state.state](fd)\n\n\nclass nbNet(nbNetBase):\n\n
def __init__(self, addr, port, logic):\n
dbgPrint('\\n__init__: start!')\n
# 初始化conn_state字典,这个字典将会保存每个连接的状态\n
# 以及连接的读写内容。\n
self.conn_state = {}\n
# 初始化监听socket\n
# socket.AF_INET指的是以太网\n
# socket.SOCK_STREAM指的是TCP\n
self.listen_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)\n
# 开启SO_REUSEADDR,这样当监听端口处于各种xxx_WAIT的状态的时候\n
# 也能正常的listen、bind\n
self.listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n
# 绑定在制定的IP和端口上\n
self.listen_sock.bind((addr, port))\n
# 指定backlog数,这里初学者可能会存在一个误区,需要解释一下:\n
有些地方把listen的参数成为“积压值”或者backlog,\n
最大连接数是最大能处理的连接数(accept了丢一边晾着是耍流氓)\n
提高并发处理能力是门学问,不单是提高“最大连接数”,两点结论:\n
1. backlog不能提高“最大连接数”\n
2. backlog不宜设置过大\n
举个栗子,假设我们的服务器是一个非常受欢迎的饭店:\n
最大连接数就是这个饭店最大能容纳的顾客人数,backlog就是门外允许排队的最大长度。\n
如果饭店点菜慢上菜也慢(服务器的处理不能满足要求),饭店将很快被被顾客坐满(最大连接数上限)\n
,门口排位如果无限排下去(backlog设置非常大),可能还不如告诉顾客现在人太多了,\n
我们处理不过来,不过等会儿再来试试。\n
想要提高服务质量只能通过提高翻桌率(服务器处理速度)来实现。\n
self.listen_sock.listen(5)
# backlog\n
# 将listen socket同样放入conn_state\n
self.setFd(self.listen_sock)\n
# 初始化epoll的fd\n
self.epoll_sock = select.epoll()\n
# 这里指定我们的listen socket只关注EPOLLIN,即connect过来的连接\n
# LT 是这里的默认, 想要ET 需要改成'select.EPOLLIN | select.EPOLLET'\n
self.epoll_sock.register(self.listen_sock.fileno(), select.EPOLLIN)\n
# 业务逻辑处理函数\n
self.logic = logic\n
# 状态机的各个状态的处理函数,这里的self.sm是一个key是字符串,value是函数的字典\n
self.sm = {\n
\"accept\": self.accept2read,\n
\"read\": self.read2process,\n
\"write\": self.write2read,\n
\"process\": self.process,\n
\"closing\": self.close,\n
dbgPrint('\\n__init__: end, register no: %s' %\n
self.listen_sock.fileno())\n\n
def process(self, fd):\n
调用业务逻辑处理函数self.logic,然后将它返回的字符串当成是\n
Server对Client的回应\n
通过约定好调用的函数原型,就可以实现比较干净的业务逻辑和网络框架的分离\n
sock_state = self.conn_state[fd]\n
response = self.logic(sock_state.buff_read)\n
# 组装给Client回应的10字节协议头\n
sock_state.buff_write = \"%05d%s\" % (len(response), response)\n
sock_state.need_write = len(sock_state.buff_write)\n
sock_state.state = \"write\"\n
self.epoll_sock.modify(fd, select.EPOLLOUT)\n
sock_state.printState()\n\n
def accept2read(self, fd):\n
这个函数主要完成accept到等待数据读取的状态转换\n
# accept一个连接之后,需要注册,初始化state为read\n
conn = self.accept(fd)\n
self.epoll_sock.register(conn.fileno(), select.EPOLLIN)\n
self.setFd(conn)\n
self.conn_state[conn.fileno()].state = \"read\"\n
# 现在accept 到 read的转换完成了\n
# 需要明确的是,我们的listen socket还是处于等待连接到来\n
# 的accept状态\n
dbgPrint(\"\\n -- accept end!\")\n\n
def read2process(self, fd):\n
这个函数主要完成read完所有请求到处理业务逻辑的状态转换\n
# pdb.set_trace()\n
read_ret = \"\"\n
read_ret = self.read(fd)\n
except (Exception), msg:\n
dbgPrint(msg)\n
read_ret = \"closing\"\n
if read_ret == \"process\":\n
# 数据接收完成,转换到process阶段\n
self.process(fd)\n
# readcontent、readmore、retry 都不用改变socket的state\n
elif read_ret == \"readcontent\":\n
elif read_ret == \"readmore\":\n
elif read_ret == \"retry\":\n
elif read_ret == \"closing\":\n
self.conn_state[fd].state = 'closing'\n
# 发生错误直接关闭,做到快速失败\n
self.state_machine(fd)\n
raise Exception(\"impossible state returned by self.read\")\n\n
def write2read(self, fd):\n
这个函数主要完成write给client回应到等待数据读取的状态转换。\n
这个情况就是我们经常听到的“长连接”\n
write_ret = self.write(fd)\n
except socket.error, msg:\n
write_ret = \"closing\"\n\n
if write_ret == \"writemore\":\n
# 写数据完成,重置各种计数器,开始等待新请求过来\n
elif write_ret == \"writecomplete\":\n
sock_state = self.conn_state[fd]\n
conn = sock_state.sock_obj\n
self.setFd(conn)\n
self.conn_state[fd].state = \"read\"\n
self.epoll_sock.modify(fd, select.EPOLLIN)\n
elif write_ret == \"closing\":\n
# 发生错误直接关闭,做到快速失败\n
dbgPrint(msg)\n
self.conn_state[fd].state = 'closing'\n
# closing directly when error.\n
self.state_machine(fd)\n\n\nif __name__ == '__main__':\n
# 这个是我们演示用的“业务逻辑”,做的事情就是将请求的数据反转\n
# 例如:\n
收到:HELLO\n
回应:OLLEH\n
def logic(d_in):\n
return(d_in[::-1])\n\n
# 监听在0.0.0.0:9076\n
reverseD = nbNet('0.0.0.0', 9090, logic)\n\n
# 状态机开始运行,除非被kill,否则永不退出\n

我要回帖

更多关于 钱包生活公司福利待遇 的文章

 

随机推荐