时隔一年,我又捡起Docker,而又放弃

   起初认识 Docker 的方式,都是从阮一峰老师的个人博客了解到的。虽然看了好几次,仍是只知其然,而不知其所以然。 与之前不同,这次我坚持看到了书的最后一页。同时,在下班后,照着书里的指引,尝试编写 Dockerfile 并构建容器。温故而知新,二刷这本书,确实能带来新的认知。

  这本书,首先介绍了 Docker 的基础架构,相关名词的概念,不同环境的安装方法。接着, 由浅入深的讲解了,基于 Dockerfile 构建的相关知识。最后,还涵盖了 Docker Compose 以及服务发现等高级用法。即使全书不到300页,仍然是满满的干货。

  一开始计划学完后,重新构建一下本地的开发环境,换掉之前使用的 Vagrant 。主要原因是,我在启动 Vagrant 时,无法正常启动 Nginx 。因为,Nginx 的配置文件在我的 Windows 终端机上,而不在虚拟机里。虽然,网上看似有解决办法,但他并不适合我。因为我的 vbox 里装的是 CentOS ,而不是 Ubuntu 。并且 Vagrant 没办法区分“启动时执行的命令”和“构建时执行的命令”,这让我很困惑。

  最后,当我发现 wsl 时,仿佛看到了新大陆。虽然,wsl 不兼容 Docker ,wsl2 又与 vbox 里的虚拟机冲突。但他的体验,绝对要比任何虚拟机都要来的好。借用知乎里别人的一句话,win10 是最好的 Linux 发行版。后来,我仍然在 wsl2 里折腾过 Docker 。但始终觉得,要学以致用才能记得住。以我目前所在公司的工作流程,使用 Docker 不太现实,还不如 wsl 直接装环境来的方便。

  wsl 真香!!!

汇编学习笔记:第五章 [BX]和loop指令

1、如果bx寄存器中的内容为 0,那么 “ [bx] ” 就等同于 “ [0] ” ,如同变量的用法;
2、mov ax,[bx] 指令,是把偏移地址为 [bx] ,段地址默认在 ds 中的数据,送入 ax 中。即:(ax)=((dx)*16+(bx));
3、段前缀:显式的指明段地址,如,mov ax,ds:[bx]、mov ax,cs:[bx]、mov ax,ss:[bx]、mov ax,es:[bx];
4、loop 指令有特定的结构,可以在汇编中实现循环功能,需要 cs 寄存器的配合。cpu 在执行 loop 指令时,会先执行 (cx)=(cx)-1,然后判断 cx 是否为零,如果为零,则向下执行,如果不为零,则转至标号处执行程序,有点像高级语言里的 for 语句;
5、inc bx 相当于 (bx)=(bx)+1,dec bx 则相当于 (bx)=(bx)-1,优点:速度比 sub 指令快,占用空间小;
6、在 8086 模式中,随意向一段内存空间写入内容是很危险的,因为,这段空间中可能存放着重要的系统数据或代码。要使用操作系统给我们分配的空间,而不应直接用地址任意指定内存单元,向里面写入。
7、程序取得所需空间的方法有两种:一是在加载程序的时候为程序分配,再就是程序在执行过程中向系统申请(摘至第 6 章,第 3 小段);

  汇编的学习,打算又放一放。这一个月来比较懒散,差不多一个月时间,才看了 122 页,大部分还是在地铁上看的。昨晚,在某东上买了本 C 语言的书。准备开始,好好地学习一门重要的语言了。
  其实呢,我这一段时间学习汇编语言,并不是打算真正掌握它。而是,准备好好地认识一下这门语言,了解它是用来做什么的,大概的一些原理。就好比我以前一直不理解,php为什么是解释型语言。
  编程世界里的语言那么多,我们究竟需要学习多少门语言,才能让自己具有竞争力。我们究竟需要精通什么样的语言,才能到35岁的时候没有中年危机,这个答案怕是没有答案。

汇编学习笔记:第四章 第一个程序

1、汇编程序从写出到最终执行过程:编写汇编源程序、对源程序进行编译连接、执行可执行文件中的程序;
2、指令:源程序中,包含两种指令。一种是汇编指令、一种是伪指令。汇编指令是指:有对应机器码的指令,可被编译为机器指令,最终由CPU所执行。而伪指令,没有对应的机器指令,最终不被CPU所执行,由编译器来执行的指令,编译器根据伪指令来进行相关的编译工作;
3、程序结构:源程序是由一些段构成的,我们可以在这些段中存放代码、数据、或将某个段当作栈空间;
4、程序返回:一个程序结束后,将CPU的控制权,交还给使它得以运行的程序,这个过程,称之为程序返回。在程序的末尾,添加返回的程序段,便可实现程序返回。如: mov ax,4c00h (换行) int 21H;

汇编学习笔记:第三章 寄存器(内存访问)

1、字单元:即存放一个字形数据(16位)的内存单元,由两个地址连接的内存单元组成;
2、DS段寄存器:8086CPU不支持将数据直接送入段寄存器(如:mov ds,1000H),只能将另一个寄存器的数据送入ds段寄存器(如:mov ds,bx);
3、在使用mov时,可以使用mov al,[0]的方式,把数据送入al寄存器,其中“[0]”为偏移地址,并且会自动取ds中的数据为内存单元的段地址。所以,mov al,[0]会把“ds:0”所在内存单元的数据,送入al中;
4、字的传送,除了有:mov 寄存器,数据、mov 寄存器,寄存器、mov 寄存器,内存单元等形式,还有:add 寄存器,数据、sub寄存器,数据,分别代表:相加、相减;
5、数据段:根据编程需要,可以将一组内存单元定义为一个段。比如,可以将一组长度为N(N<=64kb)、地址连续、起始地址为16的倍数的内存单元,当作专门存储数据的内存空间;
6、栈:后进先出的线性表,衍生出两个新命令push、pop,分别代表:入栈、出栈。用法如:push ax、pop ax;
7、SS:SP指向的是栈顶, 栈还会出现栈顶超界问题 。每执行一次push ax,相当于执行了:SP=SP-2、将ax中的内容送入当前SS:SP处;
8、栈段: 一段连续的内存空间,起止位置由我们自行安排,遵循后进先出原则。

汇编学习笔记:第二章 寄存器

1、cpu由运算器、控制器、寄存器等构成,这些器靠内部总线相连,内部总线连接CPU内部各个器件,外部总线连接CPU与主板上其他器件;
2、8086CPU有14个寄存器,分别为:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW,所有寄存器都是16位的,可以存放2个字节;
3、不同寄存器的作用各不相同,通用寄存器用于存放一般性数据(AX、BX、CX、DX),段寄存器用于存放并提供段地址(CS、DS、SS、ES),指针寄存器用于存放并提供偏移地址(IP);
4、为保证向下兼容,16位的8086CPU的AX、BX、CX、DX寄存器,都可分为2个独立使用的8位寄存器来用,如:AX可分为AH和AL、BX可分为BH和BL、CX可分为CH和CL、DX可分为DH和DL;
5、CPU读写内存时,都是通过物理地址(段地址*16+偏移地址/段地址:偏移地址/CS:IP)来访问数据;
6、DOS下debug程序的命令:R查看或修改寄存器的内容、D查看内存中的内容、E修改内存中的内容、U将内容中的内容解释为机器指令和对应的汇编指令、T执行CS:IP指向的内存单元处的命令、A以汇编指令的形式向内存中写入指令;

总结一下这个月的收获

  上个月,放弃继续学习docker后,立马拿出刚买不久的:《ElasticSearch实战》和《RabbitMQ实战指南》。打算这个月内,把这2本书者过一遍,补补知识广度的短板。7月份开始,要备战成人高考了,留给我的时间不多了。

  先说说es这本书,es这本书还好,通篇都是采用RESTFul请求示例,给我们讲解它的特性。不像那本mq,全是java代码,给我这个phper,造成了一点困扰。es是采用java语言,基于Lucene之上的搜索引擎。所以装es前,需要先安装java环境。同类型的还有Solr,不过es的优点是采用分布式模式。
  es有3个重要的概念:索引、类型和文档,类似关系型数据库里的数据库、表和行。所以,如果使用它的话,就需要把数据“索引”到es中去。内部的数据,是采用倒排索引,也叫反向索引的方式来组织的。在物理设计方面,它把同分片的
主副分片,分别存放在不同的节点上,来构建可靠的集群。即使某个节点宕机,也不会丢失全部数据。比方说:有2组分片,2个节点。他会把主分片a和副本分片b,存放到节点1。而节点2,存放着副本分片a和主分片b。
  对了,还有一个重要的概念是:映射。类似关系型数据库里的表定义,可以事先定义存储数据的字段类型。并且,还可以在第一个索引数据时,自动获取数据的类型,去“
动态映射 。映射的功能,远远不止定义数据类型那么简单。它还可以,指定某个字段的分析器类型,文档间的父子关系等。
  es有着丰富的搜索功能,默认是采用相关度排序,还可以自定义一些指标,去影响相关度,也可以指定排序字段。字段类型也比较简单,有:字符串、数值、日期、布尔。让我印象最深刻的,还是它的几个分词方式:N元语法、侧边N元语法和滑动窗口。巧妙地利用了,不同维度的字符截取方式来分词。

  随便写一写,都3点了,RabbitMQ还没开始呢!可怕!

  主流的MQ有很多,如:RabbitMQ、Kafka、ActiveMQ、RocketMQ。在阅读RabbitMQ之前,我本来在看RocketMQ,结果没看几页,就发现全部都是java示例代码,我就直接放弃了。后来,买了本RabbitMQ,结果发现还是java示例代码,最后只能硬着头皮去读。RabbitMQ是基于Erlang语言开发的,所以需要先安装Erlang环境,再安装RabbitMQ。消息中间件可以用于项目的解耦、冗余、削峰、异步通信,并提高扩展性和可恢复性。它一般有两种传递模式:点对点模式和发布/订阅模式,还可以实现RPC(远程过程调用)。
  RabbitMQ有几个重要的概念:生产者、消费者、交换器、路由键和队列。
  生产者好比寄信人,而消费者就是收信人。消息好比信件,而队列就是邮筒。生产者把消息放入队列,消费者就可以通过队列拿到消息。但是,一个城市只有一个邮筒(队列)是不够用的,所以需要邮局(交换器)去管理多个邮筒(队列)。而路由键就好比是地址,寄信的时候需要填写地址(路由键),而收信人所在的地方,也需要编排一个地址(绑定路由键)。

个人建议:先读官方文档的入门教程,因为我在书上12页的生产者代码中,也看到给队列绑定交换器,绑定路由键,比较费解。网址: https://www.rabbitmq.com/tutorials/tutorial-four-php.html

  交换器一共有4个类型: direct、topic、headers和fanout。
  使用fanout类型的交换器时,他会把收到的所有消息广播到它知道的所有队列中;
  使用direct类型的交换器时,他只会把收到的消息,广播到路由键相同的队列中;
  使用topic类型的交换器时,他跟direct类似,但他支持模糊匹配;
  使用headers类型的交换器时,他不依赖路由键匹配,而是根据消息内容中的headers属性进行匹配;

  对了,还有两个重要的概念:连接和信道。无论你是消费者,还是生产者,在操作消息的时候,都需要先建立连接。建立和销毁TCP连接是非常昂贵的,而信道是为了模拟多线程功能,而不去创建多个TCP连接,这样有利于提升性能。

docker从入门到放弃

  看了一段时间的汇编,准备先放一放。正好手上有本《第一本Docker书》,打算,先去看看,时下比较火的docker。
  当我看到第80页的时候,基本对它失去了兴趣。后面几页,我都是跳着看的。就在今天晚上,我打消了继续研究的念头。主要是我觉得,这明明是运维的锅。虽然,我最近一直被当运维使唤,也学习了一些Linux的基础。但是,我的兴趣并不在这里,我还是想多学学编程。
  当然,也不是劝大家不去学习docker。毕竟是新技术,了解一下还是可以的,但还是要确定自己的方向。学习东西,还是得跟着自己的兴趣走,不能一脑子扎进去,白白浪费太多时间。我觉得人的精力,还有脑容量,都是有限的,不可能鱼和熊掌兼得。学的东西多了,总会忘掉一些,最近的记忆力也是越来越差了。

汇编学习笔记:第一章 基础知识

1、每一种cpu都有自己的汇编指令集;
2、在存储器中,数据和程序都是以二进制形式存放的;
3、存储单元的编号从零开始;
4、计算机的最小单位是 bit ( 比特,二进制0101 ),8个bit组成一个Byte ( 字节 );
5、cpu通过总线向接口卡发送指令,总线又分为:地址总线、控制总线和数据总线;
6、地址总线的宽度,决定了cpu的寻址能力。例如:10根地址总线,寻址能力为2^10 ( 1024 或 1k );
7、数据总线的宽度,决定了cpu向其他器件,单次传输的数据量。例如:8根数据总线,一次可传输1字节( 8位的二进制数据 );
8、控制总线的宽度,决定了cpu对其他器件的控制能力。控制总线是个总称,是对一些不同控制线的集合。有多少根控制总线,就意味着cpu提供了对外部器件的多少种控制;

php笔记:引用定位

  最近,打算通读一遍php官方文档。在看到引用的时候,文档中提出:“许多 PHP 的语法结构是通过引用机制实现的”。还举例了“global引用” 和 “$this” ,都是通过引用传递的。文档中,有一句话,吸引了我的注意力,“unset $var 不会 unset 全局变量”。我也做了相应的demo测试,还真是如此。详见下代码。

[code lang=”php”]
$a = 345;
function test()
{
global $a;
$a = 123;
unset($a);
}

test();
var_dump($a); // int(123)
var_dump($GLOBALS[‘a’]); // int(123)
[/code]

如果在函数里删除变量$a,只是把函数作用域里的$a删除,并不会对全局变量$a产生影响。如下图

附上官网的这一章节:https://www.php.net/manual/zh/language.references.spot.php

git笔记 – 修改误操作

  前二周,阅读了git官方文档,感觉还是受益良多。感叹,过去的git基础太差。还经常碰见,合并远程分支到本地分支的“诡异”情况。如,https://stackoverflow.com/questions/6406762/why-am-i-merging-remote-tracking-branch-origin-develop-into-develop

情况一: 把文件add到暂存区,并未提交时,需要取消暂存, 见图一

图一

英文好的,可以直接看到说明:“使用xxx取消暂存”
这里我们直接输入 ,效果见图二 [code lang=”php”]git reset HEAD test.php[/code]

图二

情况二:commit到本地仓库后,需要取消提交,见图三、图四

图三
图四

这里我们可以输入 ,效果见图五、图六 [code lang=”php”]git reset –soft HEAD~1[/code]tips:数字1可以省略

图五
图六

除了,可以回滚到“未提交”状态,还可以直接回滚到“未暂存”状态
[code lang=”php”]git reset –mixed HEAD~1[/code]
tips:参数”–mixed”可以省略。这里涉及到git手册中“重置揭密”的知识,个人建议:去看官方文档较好 ( https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E9%87%8D%E7%BD%AE%E6%8F%AD%E5%AF%86 )

情况三:提交代码后,发现有些文件不用提交,需要从提交记录中删除,但又不删除文件本身,如:ide生成的临时文件、测试代码等。

直接运行如下代码。如果提交代码时,需要忽略该文件,可以配置到 gitignore 中。
[code lang=”php”] git rm –cached test.php [/code]