暑假实习内容记录与总结

文章目录

暑假在一家云计算公司实习,实习的形式是上课和写作业,公司会对作业进行评分进而作为选拔的依据。

实习中学到的知识与学校中实验室环境的不同,开发要求严格多了,并且实习中学到了完整的知识体系,各种地方应该用哪些技术,这些在平时某站网课中都是接触不到的,也不是网络上碎片化的博客可以接触到的,书籍中的知识也没有这么新,暂时还不太知道如果自学的话该如何得到同样系统的知识。

实习之前我也看了某站中预习内容的网课,但是实习过程中就觉得当时学得太浅了。

实习已经结束一周了,发现自己对整个实习期间的印象越来越模糊,这里就总结了每周上课的内容(Java、高并发、微服务、分布式存储、分布式计算)。

--

1.实习内容

预习内容

实习前发布了预习内容如下:

预习内容 参考资料
docker的应用 https://www.runoob.com/docker/docker-tutorial.html
k8s的的应用 https://www.kubernetes.org.cn/doc-11
Niginx的应用 https://www.w3cschool.cn/nginx/
Redis的应用 https://www.w3cschool.cn/redis/
SpringBoot的应用 https://www.w3cschool.cn/springboot/
SpringCloud的应用 http://c.biancheng.net/springcloud/
ZooKeeper的应用 https://zookeeper.apache.org/doc/r3.4.6/index.html
计算机文件系统发展历史 https://mp.weixin.qq.com/s/VZW1Iw0tbzWK-JIAktAqOw
Posix 可移植操作系统接口知识 https://zhuanlan.zhihu.com/p/392588996
分布式系统知识 《分布式系统常用技术及案例分析》- 作者 袁斌 《gPRC与云原生应用开发》(只用看 1,2,3,4,章节内容)

第一周:工程化开发与工作中常用知识

第一周依次学习了Git, Maven, Shell, 代码规范, Java, JVM。

与在学校的实验室环境不同,工程上对于Git和Maven的使用专业多了,也知道了一些工程中的实践方法。Shell脚本也是在这里新学的,之后几周中会涉及到写启动脚本。

Maven

Maven的课布置了一个作业,要求写一个Maven的打包插件,具体是使用 ZipOutputStream, JarOutputStream, Manifest 等类来操作 zip 和 jar 文件,并将 target/classes 目录下的类文件和依赖的 jar 文件打包成一个 zip 文件。大概开发了三天,一开始很懵不觉得自己能开发出来,都不知道该使用ZipOutputStream, JarOutputStream, Manifest 等类,不过硬着头皮一直做。第一周进度快,做作业的时间和上课时间冲突了,于是我在上课的时候也做,最后几乎成功了,结果打出来的包又不可执行,经历了大量的调试最后成功了,我还为我的作业写了README文档。现在觉得这个项目一点都不难了,不过经过这个项目我对Maven的知识都有所运用了。

代码规范

代码规范的课收获不太大,因为之前也没有什么工程化开发的经验,也因为我在写Maven的作业,第一周的我连DAO层是什么都不太懂,就听这种重构的课,感受不太大。不过这门课发了一个作业是重构一个使用SpringBoot框架写的秒杀项目,我就根据这个源代码学会了SpringBoot的使用和项目中如何分包的问题。

Java常用知识点

Java课是在Maven作业截止后上的,收获挺大的,讲了文件输入输出流的使用、注解、反射和Optional与Stream。在之前我这些知识都用得很少,文件输入输出流也就刚刚在Maven作业中使用了,不过后续项目中也用得多。

注解我后面用得也不多,用了也没印象,掌握得一般。

Optional和Stream是在学校中没接触的,一开始也是不会用,在公交车上补了点网课,之后第二周项目写完后也尝试修改自己的代码。另外课外看了SICP的网课,里面将函数和数据的概念融合,也讲了Lisp中lambda表达式,看了以后我最爱的单词也成closure了,然后到处学Java如何写出函数式接口,还参考Guava的一些文档,就学会了。学会了以后感觉自己写代码有点自信了。

反射是作业了,作业写一个api参数解析器。能够将 HTTP 的 queryString 格式的字符串自动映射到对象的字段上。

难点是对Container.5.Environment.2.Key=ROOT_PASSWORD这样子的其中一段解析。这里,最外层的类是Pod,其中有个字段是List<Container>类型的,而Container类中有个字段是List<Environment>类型的,Environment也是一个类,其中有两个字段。中间的数字没有实际意义,只是用来决定其在列表中的顺序,数字越小,在列表中下标越小。

要考虑的点也很多,现在也不记得每个细节了。当时通过这个作业反射都精通了,大概花了两天,也从此学会一行一行debug了,一下午4个小时一遍遍一行一行运行分析,最后成功了感觉很好。不过反射似乎也学得太好了一点,之后竟然用这个来测试接口

第一周Shell脚本也有作业,不过不值一提了,Maven插件和反射作业让这一周很紧张,但是都做完了,之后的几周也没这么困难了。

第二周:高并发知识

第二周先学习了如何搭建一个Web工程骨架,这个课非常棒。介绍了常用类库,包括Apache Commons Components, Guava, Mybatis, Redission, Lombok, Json, HttpClient, Log相关, 数据库连接池,然后是Spring相关的一切,如何通过aop来使用日志,还有一些线程池相关,全部都给了可以运行的代码,太棒了 。然后讲了如何分包,如何将开发环境、测试环境、生产环境分开。最后是度量指标和应用部署,给了很多好资料,包括启动的shell脚本、部署在docker, k8s, jenkins等的方法等,但是我没什么工程经验没什么感觉。

之后就是高并发相关的了,包括背景知识、应对技巧、最佳架构实践以及限流熔断降级。高并发这里是分为了三个不考核的小作业和一个考核的大作业,小作业都是大作业中的部分功能点提出来的,包括qps控制器进行限流、负载均衡、设计二级缓存。

大作业是编写一个订单查询系统,该系统由两个模块组成:订单查询网关 (trade-order-gateway) 和订单查询服务 (trade-order-api)。订单查询网关负责接收客户端的请求,并进行负载均衡,将请求转发给订单查询服务。订单查询服务负责从数据库中查询订单信息,并提供相关接口。该系统还涉及到二级缓存、重试机制、限流算法、日志链路跟踪、熔断降级等技术点。

我写了70几个提交。这个项目我的代码中很多地方没有组织好,有很多重复的内容,也基本上是按照之前重构课上发的代码来学习Spring的,不过写完以后也是感觉非常好。

第三周:微服务

第三周讲了:

  • 软件的架构与演进
  • 微服务体系中的服务发现与注册
  • 负载均衡机制
  • 微服务体系中的链路追踪技术
  • 微服务限流和熔断
  • 微服务体系日志收集与追踪
  • 侵入式与非侵入式框架
  • 非侵入式框架istio
  • 以及演示如何使用k8s部署istio和istio入口网关分发流量。

内容还是相当棒的,我对这一切都有了个了解,包括架构的演进、各个模块有哪些备选技术等。

作业是使用 Java 语言和 Spring Boot 框架实现一个基本的微服务架构,不使用任何 Spring Cloud 组件或现成的微服务框架/解决方案。该架构由四个应用组件构成:发现与注册中心 (register),负责管理服务的注册、注销、心跳和发现;服务提供者 (time-service),提供一个简单的时间服务,返回当前的日期时间信息和节点信息;服务调用客户端 (client),调用时间服务并进行相关处理,返回客户端信息和时间信息;分布式日志收集服务端 (logging-service),负责收集和查询客户端发送的日志信息。

这个作业我觉得很简单,当时是周五布置,写了一下午,我周六上午5点醒了起来写,然后写完了,我两天就写完了,只写了30几个提交,所有功能和加分项都写好了,所有接口也都测试得很好。然后周一的时候傻眼了,老师给的ddl是第三周的周日,我搞不懂为什么要那么长时间。最后这个作业我的所有接口都测试有误,原因是给的开发文档有歧义,简直就是狗屎。这个作业后来有高分分享,很多值得学习的,但是我觉得我的代码写得比一些后来高分分享的人还要好,挺可惜的。

第四周:分布式存储

第四周讲了(这一部分我没有学习得很好。):

  • 分布式存储与分布式存储常见架构读写流程和高可用设计。具体讲了Hadoop读写流程和内部机制,Hadoop的元数据高可用在HDFS上的实现,以及ZooKeeper。课件很详细,之前在学校也学过考过,不过我到现在还没有记住一点。

  • 分布式一致性,分布式日志复制。具体讲了有状态分布式系统模型;关于节点、网络、失败、时钟的问题;单主/多主/无主复制,同步/异步复制;处理节点宕机;复制日志的实现的几种方法;数据一致性。

  • 分布式事务。从事务的概念讲起,之后讲原子提交与两阶段提交三阶段提交,再之后讲了实践中的分布式事务。

  • 分布式存储。具体是:高容错面对的挑战、CAP、高容错系统设计方式、冗余理论、跨机房部署;NAS介绍和系统架构;

    NAS其实讲了一天,讲了它的优势、产品具体功能、整体架构、技术架构演进和与作业相关的事情,但是我没学好。

这一周的作业是写一个分布式文件系统。该系统的目标是提供一个高可用、高性能、高可扩展、易于部署和运维的文件存储服务,支持文件的创建、删除、读写等操作,并提供HTTP协议的访问接口。该系统采用元数据和内容数据分离的方式存储文件,元数据包含文件的基本信息和内容数据的三副本索引,内容数据为实际文件内所存储的内容信息。该系统还支持元数据服务的高可用和分布式一致性,内容数据的三副本写和随机一个副本读,以及文件副本不足时的自动恢复功能。

实现的时候是有四个部分:zookeeper、元数据服务metaserver、内容数据服务dataserver、客户端client,牵一发动全身,一开始完全不知道从何入手,比如我设计了一个很复杂的写流程,如果实现了就基本上大体就做完了:

创建文件/写入流程:

  1. 客户端调用元数据服务的create接口,创建一个空文件,并返回一个StatInfo对象,包含文件的元数据信息。
  2. 元数据服务在创建StatInfo对象后,选择一个内容数据服务作为主节点,调用其create接口,传递statinfo对象作为参数。
  3. 内容数据服务在本地磁盘创建一个空文件,并选择两个其他的内容数据服务作为副本节点,调用其create接口,传递statinfo对象作为参数。
  4. 内容数据服务在收到副本节点的响应后,更新statinfo对象中的ReplicaData字段,并返回给元数据服务。
  5. 元数据服务在收到主节点的响应后将其写入磁盘,并调用从节点(如果有)的commit接口写入元数据,然后返回给客户端。
  6. 客户端在收到元数据服务的响应后,创建一个FSOutputStream对象,封装statinfo对象。
  7. FSOutputStream类中的write方法可以根据statinfo对象中的path字段,找到对应的三个节点内容数据服务,并调用其write接口,传递要写入的字节数据和偏移量作为参数。
  8. 内容数据服务在收到write请求后,在本地磁盘写入数据,并更新statinfo对象中的size和mtime字段,返回更新后的statinfo对象给客户端。
  9. 客户端在收到内容数据服务的响应后,更新FSOutputStream对象中封装的statinfo对象,并继续写入数据或关闭流。
  10. FSOutputStream类中的close方法可以调用元数据服务的commitwrite接口,传递最终更新后的statinfo对象作为参数。
  11. 元数据服务在收到commit请求后,在磁盘上更新statinfo对象,并调用从节点(如果有)的commit接口写入元数据,最后返回成功或失败给客户端。

读文件流程:

  1. 客户端调用open方法,传入一个文件路径作为参数,返回一个FSInputStream对象,用来从文件中读取数据。
  2. open方法调用元数据服务的open接口,传入文件路径作为参数,获取一个statinfo对象,包含文件的元数据信息。
  3. open方法根据statinfo对象中的replicadata列表,选择一个内容数据服务作为读取节点,并创建一个FSInputStream对象,封装statinfo对象和读取节点的URL。
  4. FSInputStream类中的read方法根据statinfo对象中的path字段和读取节点的URL,调用内容数据服务的read接口,传递要读取的字节数据和偏移量作为参数。
  5. 内容数据服务在收到read请求后,在本地磁盘读取数据,并返回给客户端。
  6. FSInputStream类中的close方法关闭输入流,并释放资源。

实现的时候只能慢慢来,从client出发,先实现client/metaserver/dataserver分别仅与zk交互的,再是client和metaserver交互,再是metaserver和dataserver交互的,再是client和dataserver交互,以及dataserver之间......最后是定时文件副本恢复。

另外元数据服务的主从选举也费了一些功夫,当时对zookeeper使用没有完全弄懂就在用了,也用了比较复杂的流程来进行主从选举,之后也花了七八个commit来解决这里的各种问题,这里我没使用raft。文件副本恢复是使用了一个定时任务,这里我很多地方没有考虑完善的。

实现的时候不断通过层层抽象的方法让自己考虑的事情越来越少。感觉这个的代码我写得也挺好的,抽象出来各种模块对代码的复用。最开始读写流程的设计也是花了一些功夫,不过仅仅是设计出来了一个可以使用的流程,对于各个部分是否最优,流程的权衡等没有任何思考。

第五周:分布式计算

这一周讲了:

  • MapReduce、Spark、任务的分解与协同
  • RPC、序列化与反序列化
    • 从RPC的背景和工作流程介绍起。
    • 之后讲了动态代理,讲了Proxy类和InvocationHandler接口和cglib动态代理包。
    • 序列化和反序列化讲了一些常见的框架,包括JDK原生序列化、JSON、Hessian、Kryo、Protobuf、Avro,都给了可以运行的代码,还给了Benchmark和选型建议。
    • 网络通信,常见的网络IO模型,Netty,这里我没有掌握好,之后作业也仅仅是照葫芦画瓢使用Netty。
    • RPC框架,讲了RPC框架在RPC中的位置,之后介绍了常用框架:Spring Cloud, Dubbo, gRPC, Thrift, Akka,都讲得很详细,也给了可以运行的代码,而我也只是会照葫芦画瓢地使用,还没有掌握这些框架的结构和特点。
  • 以WordCount为例的分布式计算框架。讲了代码,通过看懂这个代码我学到了非常多,这应该是目前为止我自己看懂的最长最复杂的源码了,大大提高了我看源码的自信心,我知道了如何一直往下追踪并看懂代码,学会忽略抽象以下的东西(SICP有帮助)。之后的作业也是要根据这个框架的代码来实现一个url topn。

作业是一个分布式计算框架,该框架能够支持“计算URL访问频率TOP N”的计算服务,并为外部提供Thrift服务接口。该框架基于指定配置文件,能够自动启动一个master进程及一定数量的slave进程,并完成首次的URL访问频率计算。该框架还具有通用性,能够扩展其他类型的map和reduce任务。我大概做了如下工作:

  • 实现FileFormat接口,支持文件切分和流式读取。
  • 实现RPC通信,使用Akka框架进行master和slave之间的消息传递和动态注册。
  • 实现任务调度,根据资源和输入参数的信息,进行任务分配和执行。
  • 实现shuffle功能,使用kryo序列化进行shuffle数据的读写,并通过网络获取shuffle数据。
  • 实现ThriftServer服务,根据urltopn.thrift的IDL文件,生成服务,并实现对外正常服务,并能生产正确的结果。
  • 实现计算逻辑,编写Master/Driver类进行任务调度和管理,编写Slave/Executor类进行实际的计算。
  • 实现结果输出,使用Avro格式进行结果数据的存储。

很多都是些细枝末节的东西,比如kryo存储shffle文件,avro格式存储结果文件,thrift提供对外接口等,这些都是最后一点点慢慢做完即可。文件的切分我犯了低级错误,后来花了很久才找到。最主要的是要实现一个新的task来计算topn,就需要从继承task接口开始写一个全流程,master与executor交互时也要使用akka使用netty等。我是从WordCount的代码上改的,理解了整个流程后发现很多东西都是框架做好了,框架本身就是自带通用性的。这个作业写完以后非常有成就感,除了资源不足时我没有阻塞等待,其余的所有功能都完美完成了。不过最后剩的那个功能也不难,我感觉我总是就没有把最后一点内容完美做完的耐心,“民之从事常于几成而败之”说的就是我。

2.总结

实习分为8周,只有五周课,后面在写第五周的作业,写完后就自习了。实际上第一周的内容进度最快,之后我自认为速度很慢,到第三周就最轻松了,作业两天就做完了,做完后ddl还在一个星期之后,甚至把各种技术都当作“工程上的细枝末节”,虽然很多确实如此,比起学术研究,作为“工业产品”的技术都理应是简单易学的,但是带着这种骄傲情绪第三周的作业最后测试情况很不好所有接口都错了,不过如果稍微多留一点心眼,这个作业就是满分了。第四周开始学习分布式存储,第五周学习分布式计算,就又有大量要自学的了。

实习中几乎所有知识都是在学习过程中自学的,一开始甚至在公交上还会看网课,经过这次实习也对自己的自学能力更有信心了。实习每一天9点半上班,由于我住的远,我想要避开早高峰,我每次7点半就到了,到八点半之前公司都几乎没人,到九点钟就nsdr一下,九点半又元气满满了。早上阅读和看网课也令我收获丰富,在公交车上就看《资治通鉴》,一般早上去晚上回就能看完1.5卷,后来也在公交车上读完了这本书(之前已经读到后唐了,后面没剩多少卷了)。

实习中使用飞书,我对这个软件印象深刻,除了阅读后对方会知道已经阅读这个功能有点打扰,其余不论是文档还是各种部门的工作台服务都挺好的。我在上面翻到了所有我有权限阅读的文档,知道了组织的庞大,意识到个人的力量永远没有机构/组织大,一定要积极建设自己所属的共同体,比如个人、家、宿舍、学校、社区、国家等。

comments powered by Disqus