IP地址与CIDR

CIDR采用各种长度的”网络前缀”来代替分类地址中的网络号和子网号,其格式为:IP地址 = {<网络前缀>,<主机号>}。为了区分网络前缀,通常采用”斜线记法”(CIDR记法),即IP地址/网络前缀所占比特数。例如:192.168.24.0/22 表示32位的地址中,前22位为网络前缀,后10(32-22=10)位代表主机号。在换算中,192.168.24.0/22 对应的二进制为:

1100 0000(192),1010 1000(168),0001 1000(24),0000 0000(0)

其中红色为主机号,总共有10位。当这10位全为0时,取最小地址192.168.24.0,当这10位全为1时,取最大地址192.168.27.255。但请注意,在实际中,主机号全为0或者全为1的地址一般不使用,作为预留地址另有作用。所以第一个地址为1100 0000,1010 10000,0001 1000,0000 0001,即192.168.24.1 最后一个地址为:1100 0000,1010 10000,0001 1011,1111 1110,即192.168.27.254

因此,本例中将第三段地址数据中最小是00011000(24),最大是00011011(27),第四段地址数据中最小为0000 0001(1),最大为1111 1110(254),以上括号中数据为十进制,其前面为二进制。所以本例中192.168.24.0/22 对应地址段为192.168.24.1-192.168.27.254,共4个网段。

一、 IP地址概念

IP地址是一个32位的二进制数,它由网络ID和主机ID两部份组成,用来在网络中唯一的标识的一台计算机。网络ID用来标识计算机所处的网段;主 机ID用来标识计算机在网段中的位置。IP地址通常用4组3位十进制数表示,中间用“.”分隔。比如,192.168.0.1。

补充(IPv6):前面所讲的32位IP地址称之为IPv4,随着信息技术的发展,IPv4可用IP地址数目已经不能满足人们日常的需要,据权威机 构预测到2010年要充分应用信息技术,每个人至少需要10个IP地址,比如:计算机、笔记本、手机和智能化冰箱等。为了解决该问题开发了IPv6规 范,IPv6用128位表示IP地址,其表示为8组4位16进制数,中间为“:”分隔。比 如,AB32:33ea:89dc:cc47:abcd:ef12:abcd:ef12。 

二、IP地址分类

为了方便IP寻址将IP地址划分为A、B、C、D和E五类,每类IP地址对各个IP地址中用来表示网络ID主机ID的位数作了明确的规定。当主机ID的位数确定之后,一个网络中是多能够包含的计算机数目也就确定,用户可根据企业需要灵活选择一类IP地址构建网络结构。

A类

A类地址用IP地址前8位表示网络ID,用IP地址后24位表示主机ID。A类地址用来表示网络ID的第一位必须以0开始,其他7位可以是任意值, 当其他7位全为0是网络ID最小,即为0;当其他7位全为1时网络ID最大,即为127。网络ID不能为0,它有特殊的用途,用来表示所有网段,所以网络 ID最小为1;网络ID也不能为127;127用来作为网络回路测试用。所以A类网络网络ID的有效范围是1-126共126个网络,每个网络可以包含 224-2台主机。

B类

B类地址用IP地址前16位表示网络ID,用IP地址后16位表示主机ID。B类地址用来表示网络ID的前两位必须以10开始,其他14位可以是任 意值,当其他14位全为0是网络ID最小,即为128;当其他14位全为1时网络ID最大,第一个字节数最大,即为191。B类IP地址第一个字节的有效 范围为128-191,共16384个B类网络;每个B类网络可以包含216-2台主机(即65534台主机)。

C类

C类地址用IP地址前24位表示网络ID,用IP地址后8位表示主机ID。C类地址用来表示网络ID的前三位必须以110开始,其他22位可以是任 意值,当其他22位全为0是网络ID最小,IP地址的第一个字节为192;当其他22位全为1时网络ID最大,第一个字节数最大,即为223。C类IP地 址第一个字节的有效范围为192-223,共2097152个C类网络;每个C类网络可以包含28-2台主机(即254台主机)。

D类

D类地址用来多播使用,没有网络ID和主机ID之分,D类IP地址的第一个字节前四位必须以1110开始,其他28位可以是任何值,则D类IP地址的有效范围为224.0.0.0到239.255.255.255。

E类

E类地址保留实验用,没有网络ID和主机ID之分,E类IP地址的第一字节前四位必须以1111开始,其它28位可以是任何值,则E类IP地址的有效范围为240.0.0.0至255.255.255.254。其中255.255.255.2555表示广播地址。

在实际应用中,只有A、B和C三类IP地址能够直接分配给主机,D类和E类不能直接分配给计算机。 

三、 网络ID、主机ID和子网掩码

网络ID用来表示计算机属于哪一个网络,网络ID相同的计算机不需要通过路由器连接就能够直接通信,我们把网络ID相同的计算机组成一个网络称之为本地网络(网段);网络ID不相同的计算机之间通信必须通过路由器连接,我们把网络ID不相同的计算机称之为远程计算机。

当为一台计算机分配IP地址后,该计算机的IP地址哪部份表示网络ID,哪部份表示主机ID,并不由IP地址所属的类来确定,而是由子网掩码确定。子网确定一个IP地址属于哪一个子网。

子网掩码的格式是以连续的255后面跟连续的0表示,其中连续的255这部份表示网络ID;连续0部份表示主机ID。比如,子网掩码255.255.0.0和255.255.255.0。

根据子网掩码的格式可以发现,子网掩码有0.0.0.0、255.0.0.0、255.255.0.0、255.255.255.0和 255.255.255.255共五种。采用这种格式的子网掩码每个网络中主机的数目相差至少为256倍,不利于灵活根据企业需要分配IP地址。比如,一 个企业有2000台计算机,用户要么为其分配子网掩为255.255.0.0,那么该网络可包含65534台计算机,将造成63534个IP地址的浪费; 要么用户为其分配8个255.255.255.0网络,那么必须用路由器连接这个8个网络,造成网络管理和维护的负担。

网络ID是IP地址与子网掩码进行与运算获得,即将IP地址中表示主机ID的部份全部变为0,表示网络ID的部份保持不变,则网络ID的格式与IP地址相同都是32位的二进制数;主机ID就是表示主机ID的部份。

例1:IP地址:192.168.23.35 子网掩码:255.255.0.0

        网络ID:192.168.0.0 主机ID:23.35

例2:IP地址:192.168.23.35 子网掩码:255.255.255.0
        网络ID:192.168.23.0 主机ID:35 

四、子网和CIDR

将常规的子网掩码转换为二进制,将发现子网掩格式为连续的二进制1跟连续0,其中子网掩码中为1的部份表示网络ID,子网掩中为0的表示主机ID。比如255.255.0.0转换为二进制为11111111 11111111 00000000 00000000。

在前面所举的例子中为什么不用连续的1部份表示网络ID,连续的0部份表示主机ID呢?答案是肯定的,采用这种方案的IP寻址技术称之为无类域间路 由(CIDR)。CIDR技术用子网掩码中连续的1部份表示网络ID,连续的0部份表示主机ID。比如,网络中包含2000台计算机,只需要用11位表示 主机ID,用21位表网络ID,则子网掩码表示为11111111.11111111.11100000.00000000,转换为十进制则为 255.255.224.0。此时,该网络将包含2046台计算机,既不会造成IP地址的浪费,也不会利用路由器连接网络,增加额外的管理维护量。

CIDR表示方法:IP地址/网络ID的位数,比如192.168.23.35/21,其中用21位表示网络ID。

例1:192.168.23.35/21

        子网掩码:11111111 11111111 11111000 00000000则为255.255.248.0

   网络ID:192.168.00010111.0(其中第三个字节红色部分表示网络ID,其他表示主机ID,网络ID是表示网络ID部份保持不变主机ID全部变为0)则网络ID为192.168.16.0

起始IP地址:192.168.16.1(主机ID不能全为0,全为0表示网络ID最后一位为1)

结束IP地址:192.168.00010111.11111110(主机ID不能全为1,全为1表示本地广播)则结束IP地址为:192.168.23.254。

例2:将163.135.0.0划分为16个子网,计算前两个子网的网络ID、子网掩码、起止IP地址。

第1步:用CIDR表示163.135.0.0/20,则子网掩码为255.255.240(11110000).0。

第2步:第一网络ID(子网掩码与IP地址与运算):163.135.0.0

    第一个IP地址:163.135.0.1 结束IP地址:163.135.15.254;

第3步:第二网络ID:163.135.16.0

            第一个IP地址:163.135.16.1 结束IP地址:163.135.31.254。 

五、子网掩码和网络ID的快速计算方法

CIDR的子网掩码都是连续的1跟连接的0表示,则子网掩码有以下几种表示方法:

0000 0000   0

1000 0000   128

1100 0000   128+64=192

1110 0000   128+64+32=224

1111 0000   255-15=240

1111 1000   255-7=248

1111 1100   255-3=252

1111 1110   255-1=254

1111 1111   255

大家都知道11111111的十进制数为255,那么我们怎么来快速计算子网掩码呢?二进制的1=1,11=3,111=7,1111=15;那么 1111 1110=255-1,1111 1100=255-3,1111 1000=255-8,1111 0000=255-15这样是不是就很快呢?只要我们一旦确定子网掩码中有多少位表示网络ID,那么我们马上就可以写出子网掩码了。那么,对于1000 0000,1100 0000和1110 0000 我们又该怎么计算呢?27=8则1000 0000=128,1100 0000=128+64,1110 0000=128+64+32,所以我们不需要去记住每一个为多少,只需要做做简单的加减法就搞定子网掩码的计算。

网络ID的结果大家都知道网络ID部份不变,主机ID部分全部变为0,那么在计算网络ID时,首先看子网掩码中有多少位用来表示网络,相应在将IP 地址转换为二进制时就只转换前面几位,比如192.168.176.15/19,网络ID一共19位,则网络ID前两个字节为192.168.X.0发生 变化的为第三个字节。那么怎样快速计算出这个变化的X的值呢?我们知道第三字节只有三位表示网络ID,转换时176>128,第1位为 1,176-128=48<64,第2位为0,48>32第3位为1,剩下的计算就没有意义了,全都要转换为0,则网络ID为10100000,则网络 ID为192.168.160.0,这样计算反而出错的可能性很小。

六、 本地和远程网络概念

网络ID相同的计算机称之为本地网络,本地网络中的计算机相互通信不需要路由器连接;网络ID不相同的计算机称之为远程网络,远程网络中的计算机要相互通信必须通过路由器连接。

例1:192.168.10.14/28,192.168.10.15/28,192.168.10.16/28,192.168.10.31/28哪些是合法IP,哪些是非法IP地址?

主机ID全为0和主机ID全为1的为非法IP地址:192.168.10.15/28、192.158.10.16/28、192.168.10.31/28都是非法IP地址。

例2:192.168.10.14/28,192.168.10.15/28,192.168.10.16/28哪个不是同一网段?

网络ID相同的就属于同一网段,则192.168.10.16/28不属于同一网段。

七、子网数和主机数的计算方法

例:172.168.34.56/20,一共划分为了多少个子网,各子网可以包含多少台主机。

172.168.34.56是一个B类地址,B类地址用16位表示网络ID,题目中20位表示网络ID,则子网位数为4位,那么子网就有24次个(即从0000、0001到1111的16种变化)。

由于IP地址是32位,用20位表示网络ID,则主机ID的位数为12位,则每个子网可以包含212-2个IP地址,即可以包含4096个IP地址。

注意:为什么计算IP地址时要减2,而计算子网数目时不减2呢?IP地址减2的原因是主机ID不能全为0也不能全为1;子网就不存在这个问题。

八、 公共IP和私有IP地址

IP地址由IANA(Internet地址分配机构)管理和分配,任何一个IP地址要能够在Internet上使用就必须由IANA分配,IANA 分配的能够在Internet上正常使用的IP地址称之为公共IP地址;IANA保留了一部份IP地址没有分配给任何机构和个人,这部份IP地址不能在 Internet上使用,此类IP地址就称之为私有IP地址。为什么私有IP地址不能在Internet上使用呢?因为Internet上没有私有IP地 址的路由。私有IP地址范围包括:

A类:10.0.0.0/8

B类:172.16.0.0/12 即172.16.0.1-172.31.255.254共16个B类网络

C类:192.168.0.0/16即192.168.0.1-192.168.255.254共256个C类网络

Java面试题

  1. 重写equals方法时,必须同时重写hashCode方法?

○是√

○否

  1. 当一个线程进入一个对象的synchronized方法A之后,其它线程是否可进入此对象的synchronized方法B?

○是

○否√

  1. 下列哪个对象不可用于线程同步的实现?

○ReentrantLock

○Semaphore

○CountdownLatch

○FutureTask

○ThreadLocal√

  1. 下面哪个Set的插入和遍历顺序是一致的?

○LinkedHashSet√

○HashSet

○AbstractSet

○TreeSet

  1. 以下关于final关键字说法错误的是?

○final是java中的修饰符,可以修饰接口、抽象类√

○final修饰的类肯定不能被继承

○final修饰的方法不能被重载

○final修饰的变量不允许被再次赋值

  1. 请选择Java线程的几种实现方式?

□Runnable接口√

□继承Thread类√

□使用Excutor框架√

□Serializable接口

□Callable接口√

  1. 关于分布式系统里保证数据一致性的描述正确的是?

□可用synchronized关键字保证

□可以基于数据的版本号来实现乐观锁√

□调整数据库事务的隔离级别为串行化√

□推荐用Redis实现分布式锁√

  1. 在下列场景下,哪种排序是最快的?

场景:在一个数组里,大多数的数据是有序的,少部分是乱序的。

□冒泡排序

□选择排序

□插入排序√

□归并排序

□快速排序

  1. Redis支持的数据结构有?

□String√

□List√

□Set√

□Hash√

□Tuple

  1. 下列哪些与数据库性能优化相关?

□拆分联合索引以应对多变的SQL√

□使用外键

□Explain (Plan) √

□将嵌套查询中返回结果集较小的查询作为子查询√

□精准查询放在前,范围查询放在后面√

□尽量避免having语句√

浅谈微服务及十二要素

微服务

微服务架构是各种因素影响下的产生的一种新的架构风格。

  1. 使用传统的单体式架构应用开发系统,如CRM、ERP等大型应用,随着新需求的不断增加,企业更新和修复大型单体式应用变得越来越困难。
  2. 随着移动互联网的发展,企业被迫将其应用迁移至流行的UI界面以便能兼容移动设备,这要求企业能实现应用功能的快速上线。
  3. 随着应用云化的日益普及,生于云端的应用具有与传统IT不同的技术基因和开发运维模式,云端的庞大计算计算能力及互联网公司大量开源轻量级技术不停涌现并日渐成熟。
  4. 新的方法与工具,如敏捷,运维开发一体化,极限编程的出现。
  5. 简化的基础设施如操作系统虚拟化,容器化,基础设施即服务(IaaS),服务平台化(PaaS),以及软件即服务(SaaS)的概念和应用的深入。

受到以上各种因素的影响,微服务架构应运而生

1.    微服务定义

微服务是一个抽象统称,在不同的语境里有不同的含义。在具体的交流中,可以分为微服务架构、微服务系统、API或消息。

1.1           微服务架构

微服务架构是在单体应用高复杂度、业务单元无法拆解的背景下,为了提升交付效率和加大系统的弹性,采用将多个可独立进行开发、管理、迭代的单一功能的模块组合出复杂的大型应用系统、各功能模块使用与编程语言无关的API集合相互通讯的方式的一种新的关于系统整体结构的抽象描述,用于指导大型系统各个方面的设计。

1.2           微服务系统

采用微服务架构思路设计的系统,我们称之为微服务系统。

1.3           微服务(API或消息)

我们更倾向于把提供特定的具体的功能的可以被外部调用的实现叫做API(Application Programming Interface)或者消息,比如Rest API、ActiveMQ或者RocketMQ等。

2      微服务标准(微服务十二要素)

2.1     基准代码

一份基准代码,多份部署,基准代码和应用之间总是保持一一对应的关系。所有部署的基准代码相同,但每份部署可以使用其不同的版本。多个应用不可以共享同一份代码,可以将代码拆分独立的类库后通过依赖策略去加载。

2.2     显式依赖

通过依赖清单,明确的声明所有依赖项,在运行时,通过依赖隔离工具确保程序不会调用系统中存在却未声明的依赖项,开发环境与生产环境都应尊从。另外每个组件的依赖应该明确列出,由于多个组件存在相似的依赖,需要进行冗余依赖排除,减少版本冲突。

2.3     代码与配置分离

不建议将可配置的信息硬编码到程序中,可以存在在环境变量里,建议用配置中心存储各应用的配置,这样使用一套代码可以很方便的在不同环境上部署,启动时只需要指定配置环境,而不用改动任何代码,此配置应该与编程语言无关。

2.4     后端服务

把后端的服务当成资源。比如本地数据库,云数据库,消息服务,第三方服务,SMTP服务等,微服务系统不应区别对待本地还是第三方服务,不论使用本地服务还是使用云服务,通过URL或配置可以方便替换。禁止后端服务之间的耦合。

2.5     构建、发布、运行

严格的划分编译、发布、运行阶段,每个阶段由工具进行管理。持续集成,持续部署。如需修改运行的代码则需要重新进行构建、发布、运行三个环节,且顺序执行。三个环节可以手动执行,也可以自动执行。持续集成,持续发布一般在敏捷管理平台上进行管理。建议每个CI都只对应一套代码库。

2.6     无状态进程

应用必须为无状态应用,Session信息应该独立于应用存储,比如存储在Memcached或Redis中。需要持久化的数据应该存储于后端服务中,比如数据库mysql。在负载均衡策略上,由于应用的无状态性,所以要用轮询请求应用服务器的方式,以使各应用服务器的负载更加均衡。

2.7     数据隔离

建议只允许通过服务API 来访问服务的持久化数据,防止微服务之间隐式契约,确保微服务不能紧密耦合。不允许数据共享。微服务之间通过API或消息互相访问,也加大了微服务后台选型的灵活性,比如微服务后台数据库选型mysql还是oracle已经与服务调用者无关。

2.8     提升并发能力

进程优先于线程。通过横向扩展容器来提升吞吐能力,纵向扩展一般不推荐,比如增加内存,增加CPU核数,一般内存和CPU占用率过高都存在潜在的风险,需要优化程序逻辑。线程的使用要慎重,尽量减少线程的资源占用。

2.9     快速启动和优雅终止

在启动时应禁止自动执行的任务,及禁止同步加载大量数据,减少启动时间,这样有利于快速的对应用进行伸缩,快速响应配置和代码的变化。进程还应该在突然死亡时仍然保持健壮,比如重要数据要实时存储到后台。

2.10 开发与生产环境一致

缩小本地与线上差异,保证各环境的一致性,包括OS,容器规格,虚拟机规格,Tomcat版本,数据库版本,JDK版本,PaaS组件版本等,尽可能减少开发环境与生产环境的差异。

2.11 把日志当做事件流

应用应该把日志存储于日志云平台,不要自己存储在本地。要能够在终端看到应用的实时日志流,最好能够做到实时日志的聚合展示。通过日志要能够查询到每个服务的执行时间。

2.12 管理进程与其它应用进行使用同一份代码和配置

脚本,系统管理后台同样要用代码仓库管理,并且与应用代码保存在同一套代码库里,而且应该不受环境影响,要保证脚本可重复执行.

Mysql事务的串行化

串行读特别简单,就当成是对同一个批数据不允许并发操作,按顺序更新,插入,或者删除。

那么问题来了,同一批数据该如何界定?这是个问题。之前的看图说话中,似乎还没提到这个问题。

先看串行读,事务开启,先事务A select,然后事务B进行 update,注意,此时事务B是不可能马上提交成功的,要等事务A 提交后,事务B才会提交,这就是串行。(如果不start transaction,意味着未开启事务,那么就是自动提交,自动提交也是事务)

先看图说话:

事务A (下图B更新+1,A也更新+1)

下图为事务B 因为等待事务A的提交而超时。

基本上三种隔离级别都实验了。

对于开篇提出的疑问,“一批数据”指的到底是什么,经过实验,三种隔离级别里,都是对读取的数据行表进行隔离。

比如事务开启后先执行了select * from account,因为没where条件那就是隔离了整张表了。

所以当要求多个事务中的数据修改不能互相覆盖时,如果想用事务控制,只有串行化。这是重点!五颗星!

此时此刻应该再搞搞MVCC了。

Mysql事务的可重复读

Repeatable Read 即 可重复读。Mysql默认的隔离级别。

理解了不可重复读,再来看可重复读就简单的多,也就是不管其它事务B是否修改了该数据,事务A内读多次该数据都是一致的,当然有个前提就是事物A在多次读之前都没有对数据进行修改,插入,删除的操作,否则怎么会一致呢。

还有个小提示就是:事务A开启后,如果还没有执行任何语句,事务B进行了更新操作,那么事务A的第一次select结果一定是事物B操作后的。

看图说话:

隔离级别

下图事务A读两次,第一次读bill有1000块钱,红框表示事务B进行了update操作。

事务A

事务B更新

事务A第二次读的结果bill的钱仍是1000,与事务B更新后读出的结果不同。

事务A里读了两次都是1000,即可重复读。

可是,如果事务B更新为999块钱时,事务A进行更新操作把bill的钱减1,然后事务A再次读取,会显示Bill有多少钱呢,999还是998?在事务A执行中间,事务B进行了插入或者删除操作呢?

看图继续:

事务B

事务A

从上图可知,事务B的插入和删除,对事务A依然是不可见的,即不影响事务A的多次读的结果,也就是说仍然是可重复读即数据一致。

然而,一旦事务A有修改操作,就会在事务B更新的结果上进行修改,再次读,就会读出更新后的结果。

这么看,多次读的结果是否是一致的,非很多场景,依赖于其它事务干了什么,依赖于本事务干了什么,不可笼统的讲。

这个场景,如果拿出来面试,血流成河。

Mysql事务的不可重复读

事务的ACID属性中的I是Isolation,言外之意就是多个事务之间的数据隔离问题,所以在谈论事务时一定是在多个事务即一般意义上是多个数据库连接同时操作的数据库的情况下。单个事务内是没有isolation概念的,即单个事务内的数据无隔离性,全可视。

四种隔离级别中的

第一种:Read Uncommitted,几乎无实际用处,请忽略。

第二种:Read Committed也叫做Non Repeatable Read,即不可重复读。

这个级别是多数数据库的默认的隔离级别,但是MYSQL不是。

不可重复读?指的是什么?

首先要搞清楚,是谁第一次读、第二次读?是指在一个事务内的两次select,也就是在一个数据库链接中操作。

为何叫不可?是因为这个级别的事务A开启后,第一次select后,另一个事务B有update这条记录的操作,并且commit了,再之后这个事务A再次select,得到的结果和第一次select的结果不同,这就是不可重复读。

下面我们看下实验(mysql版本5.6.17):

表结构

表数据

设置隔离级别

事务A先select(红框上面),然后事务B(另一个数据库连接)update了记录为999(红框表示有事务B执行).

事务A:

事务B:

然后事务A再次执行select(红框下面),读出的结果与第一次不同(bill第一次有1000,第二次有999,因为两次读中间,事务B修改了bill的钱)。

这就是不可重复读,但是只是update情况,那么insert和delete情况如何?继续看下。

事务B中进行insert操作,然后事务A读一下,然后事务B再次delete,然后事务A再读。

事务B

事务A

可见,这个级别是彻底的不可重复读。

如果事务A中,先读,事务B更新,事物A再更新同一条记录的同一个字段,然后事务A再读该字段,会出现什么情况?这个字段的值该如何变化?

这个情形,不可重复读和可重复读是一致的,见下一篇《Mysql事务的可重复读》。

色诺芬

既然自制能够保证在最为平庸的事物中找到“难以忘怀的”乐趣,而试图寻找快感的大多数做法因缺乏自我主宰结果一无所获,那么自制则能比它物获得更多快感或找到最佳快感。《色诺芬与苏格拉底》,p39。

苏格拉底还是个节食主义者!