风扇摆着头,床头柜的台灯射出幽暗的光。风衣被挂在墙上,毛线手套一半搭在桌沿,利刃发出寒光,滴着血。乔是个杀手。


温热散去,乔收去风衣,带上手套,收起匕首,将书桌歪斜的书本摆直。“导演”欣赏利落的人,乔却从来不把这当作刻意。谨慎有序是他的天性。


在夜间思考,在白天沉默。乔支起双手,刚开的水在手边冒着烟。凡事总有为什么,乔只是想把它摸清而已。门口响起三声闷响,脚步远去。

订单又到了。


书架上摆满了乔的笔记。笔迹清晰整洁。他坚信,多人不成事。雨后的路灯下,乔避开光明的嘈杂。风衣滴着水,枪口还留着余热。人云亦云,厌恶之至。

一道锁,两道锁,三道锁,水温正好。一口水,两片药,三点整,思考结束。


街上的杀手不只乔一人,乔也并不愿认识所有人。朋友间少不了兵戎相见,乔手里攥着他们的鲜血,在街头,在小巷,在桥洞下。只可惜,没能分享自己的哲学。


屋顶闪过微光,乔又记起,那些曾与他四目相对的脸。就像两周前,屋里的猫走时看他的最后一眼。然后,就不再回来


乔也喜欢过春天,鸣鸟,微风,可以倚坐桌边,一整天。猫蜷卧在窗台做梦,一下午。

窗外,鹅黄柳绿。窗里,它刚搬来一周,水仙迎风跳起舞。


乔不怕失败,只忌惮那些说不出为什么的事。茶壶呼噜发响,茶叶上下翻腾。乔坐得规矩,跟猫讲着直就是直,弯就是弯,太阳就该在白天升起,然后才是月亮。猫也呼噜发响,翘起耳朵听着。


猫饿了,要吃食。水仙渴了,要喝水。乔一一满足。吃饱喝足,乔提起他的准则。猫默然,水仙默然,无人在乎。


这些日子,乔从未失误。手起刀落,干脆利索,只因不想太多,仿佛,回答了那些问题就能过好这辈子。

我是谁?我从何而来?我又将去向何方?


如今,乔空对水仙,泡茶呷茶。猫爬上他人房梁,依旧吃饱喝足,乐得逍遥。与它几次重逢,乔心里明镜儿似的知道。这道别,早就写好了。


又几次枪口的呼啸,又几次无出其右的表演。

最后,乔辞别了“导演”,走前卖了茶具,烧了笔记,放了水仙。

“导演”有点遗憾,说到,沿途保重,一路顺风。而乔蓦然莞尔。


猫走后的第六十天,乔开始苏醒。

午后五点十五分,乔飞奔在麦田边的路上。喊杀声常伴耳边,阳光把身影扯得老长。眼前的路恣意延伸着。

乔的心里很平静,他明白事情总有始有终,就像你我每天要吃饭一样简单。再见了我的刀,还有你滴过的汗。再见了我的枪,还有你冒过的烟。

天被撕裂,地在颤抖。夕阳流着血,注视着乔。而乔,曾是个杀手。

Docker

Docker

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。总之就是轻便型的虚拟环境。

考虑到ONOS的实验环境搭建不易,Docker有助于我们移植搭建好的环境。

Docker安装

1、安装软件包apt-transport-https,使APT系统能够被https解析

1
$ sudo apt-get install apt-transport-https

2、添加Docker repository key到本地keychain

1
$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9

3、添加docker软件仓库到软件源,升级软件源,安装lxc-docker包

1
2
3
$ sudo sh -c "echo deb https://get.docker.com/ubuntu docker main > /etc/apt/sources.list.d/docker.list"
$ sudo apt - get update
$ sudo apt-get install lxc-docker

注:上述操作可以使用下面的脚本完成。

1
$ curl -sSL https://get.docker.com/ubuntu/ | sudo sh

4、验证docker安装完成,可以使用下面命令测试

1
$ sudo docker run -i -t ubuntu /bin/bash

-i interactive, -t tty, -p port可以多次使用指定多个Port映射, -P端口映射随机分配

ONOS(Open Network Operation System)

ONOS是首款开源的SDN网络操作系统,主要面向服务提供商和企业骨干网。ONOS的设计宗旨是满足网络需求实现可靠性强、性能好、灵活度高。此外,ONOS的北向接口抽象层和API支持简单的应用开发,而通过南向接口抽象层和接口则可以管控OpenFlow或者传统设备。总体来说,ONOS将会实现以下功能:

  • SDN控制层面实现电信级特征(可靠性强,性能好,灵活度高);
  • 提供网络敏捷性强有力保证;
  • 帮助服务提供商从现有网络迁移到白牌设备;
  • 减少服务提供商的资本开支和运营开支。
    下面介绍ONOS安装(Ubuntu源码安装)

1 系统要求

安装ONOS对操作系统有如下要求

  • Ubuntu Server 14.04 LTS 64-bit
  • 2GB or more RAM
  • 2 or more processors

需要安装如下软件,如果不用git获取源码,GIT可以不需要安装。

  • Java 8 JDK (Oracle Java recommended; OpenJDK is not as thoroughly tested)
  • Apache Maven (3.0 and later)
  • git
  • bash (for packaging & testing)
  • Apache Karaf (3.0.2 and later)

2 安装依赖

安装apache-karaf和apache-maven

apache-karaf的版本为3.0.2或以上版本,apache-maven的版本至少为3.0,这里使用版本3.2.2。创建/Applications目录。之所以要安装到这个目录,是因为onos源码中已经设置将apache-karaf、apache-maven放到/Applications目录。这个目录也可以通过更改~/onos/tools/dev/bash_profile修改,但是为了避免不必要的操作,这里按照默认创建文件夹。

1
2
3
4
5
6
$ cd; mkdir Downloads Applications
$ cd Downloads
$ wget http://download.nextag.com/apache/karaf/3.0.2/apache-karaf-3.0.2.tar.gz
$ wget http://www.apache.org/dist/maven/binaries/apache-maven-3.2.2-bin.tar.gz
$ tar -zxvf apache-karaf-3.0.2.tar.gz -C ../Applications/
$ tar -zxvf apache-maven-3.2.2-bin.tar.gz -C ../Applications/

安装java8

1
2
3
4
$ sudo apt-get install software-properties-common -y
$ sudo add-apt-repository ppa:webupd8team/java -y
$ sudo apt-get update
$ sudo apt-get install oracle-java8-installer oracle-java8-set-default -y

正确安装后,java -version和mvn –version打印的java版本应该一致。

3 安装 ONOS

下载ONOS源码

将ONOS源码下载到合适的目录(笔者放在/home目录下),切换到1.0.0分支

1
$ git clone https://gerrit.onosproject.org/onos -b 1.0.0

环境设置

安装ONOS之前,需要设置ONOS_ROOT和KARAF_ROOT等路径,切换到root权限用户,在/etc/profile文件的最后添加如下设置:

1
2
3
4
5
export ONOS_ROOT=/home/onos/onos-onos-1.0
export KARAF_ROOT=/root/Applications/apache-karaf-3.0.2
export JAVA_HOME=/usr/lib/jvm/java-8-oracle
export M2_HOME=/usr/local/apache-maven
export PATH=$PATH:$M2_HOME/bin

保存后执行

1
2
$ source /etc/profile
$ source $ONOS_ROOT/tools/dev/bash_profile

如果没有报错,则表示执行成功
可能的错误有:

  • No such file or directory
  • No such cell: local

构建ONOS

以上的步骤一切顺利后,可以开始构建ONOS,执行下列命令

1
2
$ cd onos/ //目录可能因人而异
$ mvn clean install

安装需要5~10分钟不等.

运行ONOS

需要编辑$KARAF_ROOT/etc/org.apache.karaf.features.cfg文件

添加下面的内容到 featuresRepositories:
mvn:org.onosproject/onos-features/1.0.0/xml/features

接着添加下面的内容到featuresBoot:
onos-api,onos-core-trivial,onos-cli,onos-openflow,onos-app-fwd,onos-app-mobility,onos-gui

之后就可以启动ONOS了:

1
$ karaf clean

启动时间较长,请耐心等待。

但是,Ubuntu源码安装并不总是能够成功的。在执行ONOS_ROOT/tools/dev/bash_profile和构建ONOS时,很容易出错。Docker在这时能发挥它应有的作用。

Docker搭建ONOS环境

声明:建议使用root用户做以下操作,可以省去sudo的麻烦

1
$ sudo -s

1 获取ONOS镜像

搜索镜像

执行“docker search onos”来搜索相关的镜像,可以从STARS来确定资源的好坏。因为ONOS刚出来不久,还没有最完美的镜像。这里我们选择“ywang1007/onos-buildenv”镜像。

下载镜像

下载选择的ONOS镜像到本地机器,这里需要花费一段时间。

1
# docker pull ywang1007/onos-buildenv

pull 后面加上 -a可以下载该镜像的所有版本

查看镜像

查看已经下载好的镜像

1
# docker images

里面已经包含了下载好的镜像

创建容器

为了展开实验,我们需要创建一个容器,进行镜像内的实验。

1
# docker run -i -t -p 0.0.0.0:6633:6633  -p 0.0.0.0:8181:8181 --name ONOS ywang1007/onos-buildenv /bin/bash

值得说的是,ONOS有web界面,端口是8181,为了可以页面访问ONOS,要做两个端口绑定。容器的6633端口绑定到主机的6633端口,容器的8181端口绑定到主机的8181端口。之后宿主机器访问“http://your ip address:8181/onos/ui/index.html”即可查看ONOS状态。

创建好后,可以使用“docker ps -a”来查看当前容器情况。

-a 全部 -l 最新
和Docker容器相关的命令有

  • docker start 启动某个容器
  • docker stop 关闭某个容器
  • docker attach 连接到某个正在运行的容器
  • docker rm 移除某个停止运行的容器

docker的相关命令可以通过docker –help来得到

之后的操作类似于上一节介绍的,搭建环境,建构运行ONOS。在宿主机器上运行mininet,使用pingall命令,可以证明onos已经在工作。过程略。

好不容易搭建好的onos环境最好用新镜像的方式存储起来,方便下次直接使用。

1
2
3
# docker commit xxx onos-1.0.0 //提交一个新的镜像
# docker save onos-1.0.0 > /home/zinc-fnl/onos-1.0.0.tar //将新镜像保存起来
# docker load < /hoe/zinc-fnl/onos-1.0.0.tar

此时再次查看本机的镜像

1
# docker images

就会发现刚才保存的新的镜像。

总结

本文主要介绍了docker的安装与简单使用以及ONOS的环境搭建。从中可以看到docker对于快速搭建实验环境有很大帮助,相信未来会有长远的发展。另外,这里对ONOS的性能并未做详细分析,笔者将在日后通过实验对ONOS进行考察。

副产品

实验过程中,因为对profile文件做过修改,曾出现过开机无法登陆的情况。orz..

问题:登录成功后,自动跳转回登陆页面

解决方法:

  1. Ctrl+Alt_F1切换到文本模式
  2. 将在profile和bash_profile做过的修改撤销掉
  3. find Xauthor* 将查到的所有文件要么sudo chmod 777 要么rm掉
  4. startx切换回来重新登录即可

2月2日,二月份第一个工作日。老大道佳和同事阳仔来了,技术组的三人总算全部到齐。再加上辰光大师兄,讨论时总算有了许多技术成分加入。此时,对产品未来开发的开发变得有了冲击和富有信息量起来。期间,道佳和阳仔(其实阳仔能力很强)提到了代码重构的概念。自己之前也有所感悟,这次找到共鸣有些高兴。

关于重构

有前几篇日记的缺点做借鉴,这里分点列出我的想法,力避废话和漫无头绪。

重构是经常出现的

起因是,身为技术的我们接手的是外包团队的一期作品,随着更高产品需求的提出,代码自然做了一番又一番的增删改查,渐渐地,我们愈发察觉到推倒重来似乎比继续修改来得更长远和轻松。今天对员工权限模糊问题的讨论是压倒骆驼的最后一根稻草。在讨论时,道佳提到重构是程序员避不开的环节,所谓两月一重构。我认为很有道理,诚如辰光在之前所说,产品的商业模式是会随市场反响改变的。这样,阳仔的事例就很好解释了——他在之前的创业团队当过技术,写代码时,他说到“我写的代码只能用2个月,这两个月后恐怕需要你们找跟你们一起做下去的技术重新写一遍。”

重构来自新需求或新思想

产品在推出后,导向不可避免受到外界的影响。补丁打多了,衣服自然变得不适合穿。老版的代码经常跟不上方向的迅速变化,重构是最理想也是最有效的解决办法,治标且治本。另外,这里新思想是指对数据结构或身份权限等基本模型有了更深的认识抑或外界因素迫使基本模型做出适应(如用户量的庞大将考验数据表的设计),这次我们将要作出的重构一部分就是因为这个原因。

重构是产品与技术的平衡点

产品设计和技术开发的思路刚好是两个不同方向。产品设计讲究MVP(Minimum Viable Product ),意为产品的最初设计一定要抓住核心,把产品的主要价值展现出来即可。拿给用户反馈后,再看情况做后续设计。因为,这样在成本上最节省,且成功概率最大。“迭代”一词在这里是最佳的形容,推出=>反馈=>复推出,如此周而复始,雪球越滚越大。归功于互联网的快速,可以“小步快跑”的传统行业互联网化将有很美好的场景(可惜的是,汽车等传统行业做不到),在短期内滚成很大规模。因此,初期产品追求短小而精悍,很忌讳全面。

理想化的技术恰相反,毕竟只有对产品有了全面细致的思考,才能使保证产品在技术上的长时间可靠性。如,模型设计,数据表设计。这些正像大厦的地基,地基牢固,楼才搭得高。可是,绝大多数情况,产品等不了那么久,没有全面思考调研的时间,只能像上文提到那样,先做出突出主体的一部分。这样技术就不得不在新需求的压力下,对地基进行小范围修改,以保证产品的可靠性。可以想见,这样搭上去的楼注定不会牢固。

重构恰好是两者中的平衡点。重构给了技术喘口气的时间,也能满足产品方面的新需求。正是由于它的普遍存在性。很多公司其实是一边打补丁,一边给自己铺后路设计新技术架构的。

MVP与产品成功三内因

上文中也提到了,产品的设计是有讲究的。在初期设计时,一定要把握住MVP的思路,只呈现核心价值,用最小可验证产品证明它的可行性。微信就是个很典型的例子,1.0只推出了聊天功能,之后的摇一摇,朋友圈,支付等都是一点一点加上去的。充分的缓冲时间和较快的互联网产品周期,让它能稳步上升。它的内因是,未来无法预知,最小代价实验,随机应变是最放心的。好的产品经理不用识别未来,只要能识别好产品现在的走向就不错了。反过来看初期,若有的产品设计的面面俱到或是团队承诺已考虑到未来,多半走不远。

产品在设计上有成功的三内因。一,满足刚需;二,用户黏性;三,用户体验。这里以师兄提到的找朋友出去玩的app来讨论。

满足刚需

刚需是什么?就是在某种场景下,满足某一部分人的必需。以例子为例,它满足了在找不到熟人却想进行体育活动等时的需求。刚需最好别无取代,当有所取代时,可以尝试缩小用户群,提高针对性。

用户黏性

满足了刚需,就会有人用。但这还不够,足够的用户黏性才能保证产品活下去。黏性的最好衡量因素就是使用频次。以例子为例,休闲活动对于大多数人来说一周一到两次,这样的频次实在不算高。

用户体验

用户体验即产品价值。价值=值 - 价,只有用户使用产品时的显性+隐性花费小于得到的体验,才会被留下来。即产品大于用户的预期。它是用户黏性的保证。

写了这么多篇日记,似乎以产品为多了。道佳、阳仔过来后,但愿在技术上也能得到真知灼见。

此次论文仿真中,需要对虚网映射的过程进行改进。在原先只考量CPU和带宽的基础上为链路增加VLAN属性,并在映射过程中分配VLAN、检测VLAN是否用尽。经过三天的阅读,这里把仿真包里embed.c这个主要文件的各函数分析在下面,方便日后修改。

数据结构

数据结构存储在embed.h中。

  • struct_link 描述物理链路,有from、to、带宽三个属性
  • request 虚网请求,有split, node, links, CPU[], bw等多个属性。
  • substrate_network 底层物理网络,有nodes, struct_link links等属性
  • s2v_node 被映射了虚网的物理节点的状态
  • s2v_link 被映射了虚网的物理链路的状态
  • path 逻辑链路映射成的多段物理链路
  • req2sub 描述虚网映射的实时映射关系
  • shortest_path 最短路径,通过Floyd算出(用于链路映射)
  • bneck 瓶颈节点

相关函数

节点映射

find_proper_node

目标:在当前底层物理网络中寻找rest_cou最适合(rest_cpu和request CPU最近,且大于它)当前虚节点的节点。

find_MinNeighborResource_node

目标:在当前底层物理网络中寻找rest_cpu满足要求,且自资源最不丰富的物理节点

衡量标准:节点rest_cpu * sum(rest_bw)

find_MaxNeighborResource_node

目标:在当前底层物理网络中寻找除了exclude节点外的rest_cpu满足要求的,且自资源最丰富的物理

节点

衡量标准:同上

find_available_node

目标:在当前底层物理网络中,从一随机起点出发,寻找第一个rest_cpu满足要求的物理节点

map_node_greedy

目标:在当前物理网络中,为特定index的虚网映射进行节点映射,哟西按占用资源最丰富的节点,成功则更新物理网络的状态(s2v_node, s2v_link),失败则对已映射的节点进行拆除。

map_node_star

目标:在当前物理网络中,为第一个请求节点分配资源最丰富的节点,其余逻辑节点随机分配,成功则更新物理网络的状态(s2v_node, s2v_link),失败则对已映射的节点进行拆除。

链路映射

由于链路映射算法大多很复杂,这里将算法流程也一并列在下方。

unsplittable_flow

目标:为不可分割流进行链路映射

算法流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
0  初始化变量,位置分配内存空间
1 死循环
1.1 找到请求中状态满足要求(完成了节点映射)且收益最大的请求,直到状态全部更新
1.1.1 存储id,改变其标志位
1.2 判断该请求状态,与是否可分割
1.2.1 找到该请求的所有逻辑链路
1.2.1.1 找到它们的起始、终结物理节点
1.2.1.2 判断它们是否已找到之间的最短路,否则继续寻找
1.2.1.2.1 Floyd矩阵找下一跳
1.2.1.2.2 下一跳若不可达,break
1.2.1.2.3 寻找有没有实体链路对应Floyd的下一跳
1.2.1.2.4 如果没有,或者有但是rest_bw不够,break
1.2.1.2.5 吧路过链路的可用带宽减少,将当前链路存入到路径数组中
1.2.1.3 如果上一步失败,给sub1(底层物理网络)划分内存空间,在sub1里删除上步出现问题的链路
1.2.1.4 在sub1里算出Floyd矩阵,并存储在临时变量里
1.2.1.4.1 一个类似于1.2.1.2的循环
1.2.1.4.1.1 若还不行,break到1.2.1.4.2;若可以减少可用带宽,存入到路径
1.2.1.4.2 返回错误物理链路、虚拟链路、虚网请求id
1.2.1.5 存储当前算出的路径,与逻辑链路一一对应
2 将状态标志位全部清零
3 死循环
3.1 找到请求中状态满足要求(完成了节点映射)且收益最大的请求,直到状态全部更新
3.1.1 存储id, 改变标志位
3.2 判断该请求状态,与是否可分割
3.2.1 更新时间与链路状态值
3.2.2 为请求内的spath赋值(len, bw)
3.2.2.1 为spath内的各段物理链路赋值
3.2.2.2 更新物理网络链路状态
4 释放临时变量空间
5 返回-1(虚网请求成功标志)

multicommodity_flow

目标:打印基本信息

算法流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1  打开测试文件
2 指定范围内检测有误状态符合条件的请求,
3 若没有,则返回-2并关闭文件
4 打印出满足要求的链路总数
5 打印基本信息到文件
6 打印ARC COSTS到文件
7 打印ARC CAPACITIES到文件
8 打印NODE INJECTIONS到文件
9 打印ARC MUTUAL到文件
10 打印NETWORK TOPOLOGY到文件
11 打印LOWER AND UPPER BOUNDS到文件
12 打印SIDE CONSTRAINTS到文件
13 关闭文件对象
14 运行lintest文件
15 返回 0

检测

check_flow

目标:检查映射情况

算法流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1  打开test文件,初始化变量
2 查找STATUS字段,停在此处
3 若不可执行,且阶段 0,则关闭文件,返回 -3
4 若不可执行,且阶段 1,则继续
4.1 查找VARIABLE字段
4.2 在每条链路上查找已使用过的情况,为s2v_link赋值
4.3 查找SIDE CONSTRAINTS字段
4.3.1 找到过载最严重的链路
4.3.2 找到该链路占用最多贷款的租户ID,及其占用带宽,并确定请求ID和虚拟链路ID
5 其余情况,查找OPTIMAL字段,若找到,则继续
5.1 查找VARAIABLE字段
5.2 在每条链路上查找已使用过的情况,为s2v_link赋值
5.3 为v2s赋值
6 关闭文件,释放内存
7 打印租户ID或-1(成功标志)

资源分配

同样,算法复杂,将具体流程列在下面

allocate

目标:整合节点、链路映射完成虚网映射的核心部分

算法流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1  为变量s2v_node,s2v_link,v2s划分空间,赋初值
2 为节点数组req_count清零
3 将请求按收入大小排序,找出最大收入者,为它进行节点映射,知道请求的节点映射全部完成
4 若全部未完成节点映射,返回-1
5 初始化链路映射相关变量
6 找到瓶颈节点,并进行链路映射(尝试)
7 若映射成功或链路可分割,用新方法找到瓶颈节点
8 循环:
8.1 如果上一步尝试成功,为s2v_node, s2v_link赋值,跳出循环
8.2 否则,计算这一批次的cost之和
8.3 找出剩余资源最少的节点ID,及其剩余资源
8.4 随机从上面移除一个虚拟节点
8.5 找到这个节点以外资源最丰富的节点,成功则映射到这个新节点;否则映射请求失败
8.6 检查有误未完成链路请求的虚网请求,无则跳出循环
8.7 若时间正忙而无法映射,try=门限+1,找到未完成的请求ID
8.8 cost清零,try+1,打印try次数
8.9 若try > 尝试门限,释放资源,更改状态,还原try
8.10 否则,找到瓶颈链路上的任一节点外的资源最丰富的节点
8.10.1 若找到,则映射;否则这个请求失败
8.11 检查链路映射是否完成,为s2v_node, s2v_link, v2s赋值
9 检查当前瓶颈节点,尝试链路映射
10 为s2v_node, s2v_link等赋值,用cost防止重复操作
11 检查新映射是否cost更低,是则更新
12 #允许迁移则继续向下
13 计算原始cost,释放原始映射资源,进行新的映射
14 新的映射成功则计算新cost,否则返回 0
15 新的cost是否更小,是则迁移,否则不做操作
16 还原s2v_node, ltmp
17 用unsplittable映射计算一次cost,若新的cost更小,则迁移;否则不作操作
18 更新s2v_node, s2v_link v2s
19 返回 0

辅助

calculate_cost

目标:返回指定范围内的虚网请求cost之和。cost算法同上

筛选标准:完成链路映射

exist_req

目标:查找是否存在完成了节点映射,未完成链路映射的请求。存在,则返回0,否则返回-1。

主函数 main

算法流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1  为v2s, s2v_node, s2v_link, sub, req 赋初值
2 打开底层网络文件
3 为sub赋node(sub.s2v_nod(req_count,rest_cpu,cpu),sub.link(from,to,s2v_l,rest_bw))
4 关闭文件
5 循环打各req的文件
5.1 为req的revenue/nodes,links,split,time,duration,topo)赋值
5.2 循环为req的cpu,link.from,link.to,link.bw赋值
5.3 计算出revenue
6 关闭文件
7 为临时变量s2v_node/ltmp2/v2stmp2/spath分配内存空间
8 计算得到spath值
9 初始化临时变量
10 循环:
10.1 循环检测所有完成链路映射的请求,为done_count+1
10.2 更新done,rev,cost,map状态,若映射完成则释放资源
10.3 计算当前req.rev/cost/count
10.4 写入当前数据到文件
11 为当前所有请求进行映射
12 依次次检测所有请求状态,更新未请求成功的状态与错误计数器
13 打开stat文件
14 为成功的虚网请求释放资源
15 计算当前req,dev/cost/count
16 写入当前数据到stat文件/trace文件
17 关闭文件
18 返回 0

技术总结

在和辰光师兄共事这么久后,深感自己在技术外的眼界(诸如产品、商业模式甚至更广的看法)和收获今非昔比。但是,对于追求实效和本质的我来说,技术的本质不能忘。若这些日子以来,只是富士康式地劳动,而不去反思技术,便丧失了实习的大部分意义。因此,尽管web编程,php后台,前端设计这些我以后可能用不上,但是开发思想是共通的,这里总结写收获在下面,希望日后再翻起,会觉得有所帮助。

关于调试技巧

开发和调试一定是共存的。因为大家的运气不会好到一次通过。适当的调试技巧有助于更快地完成需求(即设计的功能)。web编程的调试较有IDE环境的调试要更困难些,因为它project的概念并不明显,且web编程是多种语言的综合。包括php,asp等后台技术,html,javascript,css等前端技术。在没有编程环境下的调试,web也有它自己的style.

工具

浏览器的开发者工具是调试的利器。里面提供的element,network,sources,console等功能可以在前、后端给开发者反馈。以下就我的实践分别介绍之。

  • Element里可以看到网页源代码,各标签的格式。这里主要完成:1. 对css或是class样式设计进行反馈,开发者可以实时改变样式,所见即所得。觉得合适后,直接在后台照抄Element里的设置即可。2.观察有无标签错位或是id,class有误的情况,这个是html代码不能直接给你答案的。综上,前端应用较多
  • Network里可以看到页面呈现过程中所接受的文件。这个对于后台尤其是ajax开发则来说是极其重要的。这里有几点可以注意的:1.接受到的究竟是哪些文件,有需要的文件没有接收到么;2.点击文件后看到的内容是不是想要的,能不能反映问题。之所以说ajax很需要它。因为普适的var_dump大法在这里只有借用Network才能看到结果。
  • Sources主要用在对代码尤其是js代码段进行带断点的调试,alert大法固然好用,复杂的循环或选择结构存在时,断点会让你方便许多
  • Console也是前端大杀器。主要用于js调试。1.它能显示js error,这些会让js实效,但是它在页面是绝不会呈现出来的。2.能直接通过cli的方式检测js语句是否正确,磨刀不误砍柴工,这能让你能提高你写js时的成功率。
  • 剩下的就是Resources最常用,主要是因为它的记录cookie和session的功用。

方法

网页的呈现一般在编写完代码之后,除了浏览器的开发者工具外,php和js也有类似于printf,cout大法这样的调试方法。(说到这,顺便吐槽一句,IE的F12经常崩溃,chrome的Ctrl+Alt+I就从未遇到过这样的问题。且chrome的还有测试移动端甚至网速的定制,很对我胃口)php里最常用的就是var_dump()+die,它比printf强大的地方在于,它能把变量的详细情况呈现出来,谁用谁知道。js我没有研究过,但是alert()+return false(后一部分可以不要)已经很够用了。

思路

1.当程序原理上正确无误时,所有问题总会有原因。

2.二分法在猜测上总是效率最高的,优先将断点设置在段的中间位置。一步步寻找,答案就出来了。

关于常见问题

错误是web编程里的家常便饭(其他编程也是如此)。但实际上,很多错误的起因却是一样的。这里列举一些常见问题的原因。

  • 不匹配问题。这类问题包括大括号不匹配(很常见),标签不匹配,特殊语句不匹配。页面乱码或错得离谱时,很可能就是它导致的。
  • 有多余的无意义字母夹杂。这类问题包括夹杂在关键字里,夹杂在标签里,夹杂在语句里,夹杂在变量里甚至夹杂在空白处。第一、二、四种情况会报错xxx未定义,第三、五种情况则和具体位置有关。因为web编程多半使用vim远程完成,快捷命令极多的vim会让这种情况较为常见。
  • 没有预防特殊情况。包括空值或者负值等临界情况。这类问题比较隐蔽,一般不会出现,但是出现就可能导致重要问题。不过,比较好的是,加上检验语句还是不费功夫的。
  • 缺少空格。看起来可笑,实际却很常见。尤其在sql语句的处理上最甚。因为后台的sql基本上都是拼接而成的。所以字符串连接时若缺少了空格就会报sql错误。暴露数据库是很危险的。其他的,若html标签的属性间忘了加空格,属性值就会不起效果。
  • 误删或错误字符。这个也很常见。短的包括尖括号导致失配,长的包括语句段。不过好处在于,vim的u命令是很好用的。实在不行,还有git一直在监控。
  • 。。。。。。
    一般的错误问题都不会太大,多半是马虎粗心导致,掌握好上面说的调试方法,还是比较容易发现并修复的。

关于对vim和git的理解

因为需要在服务器上做操作,我学会了vim,并爱上了它。因为团队开发需要对项目的版本进行管理,我又学会了git,并爱上了它。它俩有个共同点,就是注重效率和轻便,但是功能强大。以下,分别谈点自己的认识。

从vim开始。vim不是编译器,更不是IDE,它只是个文本编辑器。但是配合了插件的vim使用起来和IDE一样顺手,甚至更方便。vim的特点很明显:1.纯命令行操作,鼠标可以扔掉了;2.极多的快捷键,若能熟练掌握,会相当方便。第二点是vim上手难的原因,但也是它厉害的原因。删除、选定、查询、替换等复杂的功能,vim几乎都能一键完成。我现在正在使用的vim配合了cscope.nerdtree,ctag。cscope可以寻找变量或函数的定义,nerdtree可以切换工作目录,ctag可以查看变量,函数列表,通过部分文字在工作环境下查询文件。这让代码的编写很是轻松。另外,vim的fold,补全等功能和配色也让它在快捷的同时达到了IDE的效果。桌面环境很吃资源,vim的存在让web程序员们能愉快地编程。

git是种习惯,而不只是工具。git的本地commit和鼓励分支的特点不止影响了技术。文档尤其是编程格外需要数据的安全性和可恢复性。git这个版本控制工具让程序员们可以无后顾之忧地修改文件,并且让团队间的合作变得简单可行。因为有rebase,git的本地提交的弊端被很好弥补了,多次细致的提交能让代码改变更易阅读;另外,由于git存储文件的思想和指针很类似,因此它鼓励分支并不会加重自己的负担,从而让项目开发限制更小。

对于技术方面的整理就先到这么多,有些积累说得清,有些积累说不清,说得清的我尽量写在这里,说不清的希望也当成为习惯留在脑海。

补充:商业模式

之前和辰光师兄交流时谈到的商业模式难以抄袭的问题,忘记记录下来,今日偶然想到,仍觉很有道理。这里补充记录下我的理解。

互联网产品的同质性很严重,越来越难难找到独一无二的产品。因为,只要有产品出现,简单的复制技术,就可很快的推出相仿的山寨版。阿里、腾讯、百度就可如此,技术的复制是很快的,流量和用户习惯又由他们把握。所以,这个年代,即使互联网市场风生水起,光靠点子进行互联网创业,最好的归宿也只有被BAT三家收购,卖个好价钱。这自然是创业者不想见到的。既然技术的抄袭难以避免,为何美团和饿了么仍然活得好好的,滴滴和快的也能共存,因为商业模式是抄不了的。

我们不妨对比一下,技术的抄袭抄过去的就可以了,我雇两倍的人、出两倍的价钱挖人才,就肯定能在同样时间做出更好的作品。商业模式的抄袭抄过去的一定不管用,因为,你只能看到竞争对手过去的规划,而不能看到他将来的举动。所以,这种抄袭是不靠谱的,只能跟着原创者的屁股后面走。正因此,做产品不只是技术问题,好的商业模式规划能让产品升华。

推而广之,这是否能应用到其他方面呢。总结起来就是,你很难做第二个谁谁谁。正是因为你猜不透他下一步要做什么,上一步在以后的规划中起着什么作用。这也从另一方面体现出实现规划的重要性。

0%