0%

如果有什么错误的地方,希望指出。

在之前学习 Spring Boot 项目的时候,使用过 Dockerfile 来构建生产 Docker 镜像 —— Spring Boot 在 Docker 上部署,在之前的文章中稍微介绍了两种构建 Docker 镜像的方法,一种是基于 Dockerfile,一种是基于 pom.xml 内的插件直接构建。同时在之前的博文中简单介绍了一点关于 Dockerfile 的内容,这篇文字主要是详细了解下关于 Dockerfile 中的一些命令。

使用 Dockerfile 构建镜像

镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。

Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

比如构架一个 nginx 镜像:

1
2
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

FROM 指定基础镜像

所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。就像我们之前运行了一个 nginx 镜像的容器,再进行修改一样,基础镜像是必须指定的。而 FROM 就是指定基础镜像,因此一个 Dockerfile 中 FROM 是必备的指令,并且必须是第一条指令。

在 Docker Store 上有非常多的高质量的官方镜像,有可以直接拿来使用的服务类的镜像,如 nginx 、 redis 、 mongo 、 mysql 、 httpd 、 php 、 tomcat 等;也有一些方便开发、构建、运行各种语言应用的镜像,如 node 、 openjdk 、 python 、 ruby 、 golang 等。可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。

Read more »

记录 Dcoker 使用过程中的一些命令

在之前的一片文章——Docker —— Docker 简单介绍 中介绍了 Docker。这篇主要是记录一些 Docker 的实际使用情况,以后再使用过程中如果有新的命令,也会记录。

关于 Docker 的安装,网上有很多的教程,这里就不一一介绍了,主要说下关于 windows的安装,需要注意window版本必须是企业版,不然不能安装 Docker for Windows,主要是它需要Windows的 Hyper-V 功能,不然只能安装 Docker 之前的 DockerToolBox。

镜像

获取镜像

在 Docker Hub 上有大量高质量的镜像可以使用,只需要使用

1
docker pull <镜像名>

运行镜像

1
docker run -it <镜像名>

docker run 就是运行容器的命令,具体格式下面讲解下:

Read more »

最近在看 Spring Cloud,买了本翟永超的《Spring Cloud 微服务实战》,感觉里面讲的挺详细的,只是书本里面的版本相对于官网来说,还是有些落后的,不过作为入门书籍还是可以的。

今天在一个公众号里面看到一篇面试的文章,里面有一个问题问的是负载均衡,于是想起了 Spring Cloud 的 Ribbon 负载均衡策略。在Spring Cloud Ribbon 中,RestTemplate 使得 Ribbon实现了自动化配置,同时通过 @LoadBalanced 还能开启客户端负载均衡。打算好好的整理下关于负载均衡的算法策略,梳理下用的比较多的几种。

在Spring Cloud 中,负载均衡策略都是 继承 AbstractLoadBalancerRule

轮询策略(默认,RoundRobinRule)

轮询策略标识每次都顺序取下一个 provider,比如一共有5个,第1次去第1个,第2次取第2个,以此类推。

随机策略(RandomRule)

该策略实现了从服务实例清单中随机选择一个服务实例功能。

权重轮询策略(WeightedResponseTimeRule)

该策略是对 RoundRobinRule 的扩展,增加了根据实例的运行情况来计算权重,并根据权重来挑选实例,已达到更优的分配效果,响应时间越长,权重越小,被选中的可能性越小。

它的核心:

Read more »

本篇只是也是本人在学习了解 Docker 的记录

现在在互联网公司中,Docker 的使用已经非常普遍了,在一些大公司中,都在内部实现容器化(PS:这些也是网上了解到了)。Docker 是一个划时代的开源项目,它彻底释放了计算虚拟化的威力,极大提高了应用的维护效率,总之,Docker 容器化给计算机行业带来了大变革。Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。

下面是传统虚拟化方式和 Docker 的比较。传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。


如果了解Docker —— 容器的隔离与限制后,会发现上面关于Docker的描述不是很正确,对于容器来说,其实是运行在宿主机上的,而不是Docker Engine 上。

container-w150

为什么使用 Docker

更高效的利用系统资源

由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。

更快速的启动时间

Read more »

Redis系列:

复制

在 Redis 中,用户可以通过执行 SLAVEOF 命令或者设置 slaveof 选项,让一个服务器去复制另一个服务器,被复制的叫主服务器(master),对主服务器进行复制的叫从服务器(slave)。

命令是在从服务器上执行的。

旧版复制功能

对于初次复制,旧版复制功能能够很好完成,但是对于短线后的复制来说,其效率非常低。主要是这种复制对于短线后的从服务器来说,会把主服务器的所有 RDB 文件发送给从服务器。
SYNC 命令是一个非常耗费资源的操作。每次执行命令,主从服务器需要执行下面操作:

  • 主服务器需要执行 BGSAVE 命令来生成 RDB 文件,这个操作会耗费主服务器大量的 CPU、内存和磁盘I/O资源
  • 主服务器需要将自己生成的 RDB 文件发送给从服务器,这个发送会耗费注册服务器大量的网络资源,并对主服务器响应命令请求的时间产生影响
  • 接收到 RDB 文件的从服务器需要载入主服务器发来的 RDB 文件,并在载入期间,从服务器会因为阻塞而没办法处理请求

新版复制功能

PSYNC 代替 SYNC 命令来执行复制的同步操作。PSYNC <runid> <offset>:其中 runid 是上一次复制的主服务器的运行ID,而 offset则是从服务器当前的复制偏移量,接收到这个命令的主服务器会通过这两个参数来判断应该对从服务器执行哪种同步操作。

Read more »

现实生产环境中为什么需要分布式锁?

在现在的公司的生产环境中,一个项目的部署最起码需要两台服务器,你不可以在你产品上线部署的时候,不让用户使用你们公司的产品,而且分布式部署,通过Nginx的负载均衡,也可以减轻单台服务器的压力,带来性能和效率上的提升。那么问题来了,在分布式部署产品的时候,就会产生一个问题,如何保证数据的一致性。当某个资源在多个系统之间,存在着共享的时候,为了保证大家访问这个资源数据是一致性的,就必须保证统一时刻只能有只有一个客户端出来,不能并发执行。单机部署,我们需要考虑并发问题,我们往往采用线程间加锁的机制。但是在分布式系统时代,为了实现我们之前的问题,就必须考虑分布式锁了。

分布式锁指的是在分布式部署环境下,通过锁机制来让多客户端互斥的对共享资源镜像访问。

目前主流的分布式锁的技术:

  • 基于数据库实现
  • 基于Redis实现(本篇主要讲的内容)
  • 基于Memcached实现
  • 基于 ZooKeeper实现

基于数据库实现

基于数据库实现分布式锁,主要是依靠数据库的乐观锁或者悲观锁来实现。这里可以看下我之前的博客—MySQL数据库锁机制

基于乐观锁

在数据库表里面引入一个版本号(version),通过这个字段来控制数据是否更新。

基于悲观锁

Read more »

现代操作系统中,运行一个程序时,会创建一个进程。现代操作系统的最小调度单元是线程,在一个进程中创建多个线程。

Java 线程状态

  • NEW:初始状态,线程构建但没有调用 start 方法
  • RUNNABLE:运行状态,Java操作系统中的就绪和运行状态的统称
  • BLOCKED:阻塞状态,表示线程阻塞于
  • WAITING:等待状态,表示线程进入等待,进入等待状态表示当前线程需要其他线程做出一些特定动作(通知或中断)
  • TIME_WAITING:超时等待状态,该主题不同于 WAITING,它是可以在指定时间内自动返回
  • TERMINATED:终止状态,表示该线程执行完毕

启动

启动使用 start() 方法,含义:当前线程同步告知Java虚拟机,只要线程规划器空闲,应立即启动调用 start() 方法的线程。

Thread.join() 的使用

如果线程A执行了thread.join()语句,其含义是:当前线程A等待thread线程执行终止之后,才从thread.join()返回。线程Thread 还提供 join(long millis) 和 join(long millis, int nanos) 两个具备超时特性的方法。这两个方法表示,如果线程thread在给定的超时时间内没有终止,那么将会从超时方法中返回。

start 和 run

start()只是让线程处于就绪状态。告诉CPU我已经准备好了,可以调用我了。而run()则是直接按顺序执行。

wait() 和 sleep()

Read more »

Git提交规范

Git Commit 规范:

1
<type>(<scope>):<subject>

具体里面参数的含义:

type

用于说明 commit 的类别,值允许使用下面7中标识:

  • feat:新功能(featur)
  • fix:修补bug
  • doc:文档(documentation)
  • style: 格式(不影响代码运行的变动)
  • refactor:重构(即不是新增功能,也不是修改bug的代码变动)
  • test:增加测试
  • chore:构建过程或者辅助工具的变动

scope

用于说明 commit 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同

subject

Read more »

欢迎指正。

MySQL 作为现在互联网行业使用最广的数据库之一,最近几天刚好看到两者的区别,就想了解下数据库的存储引擎。MySQL的主流数据存储引擎有 InnoDB 和 MyIsAM 两种。

InnoDB存储引擎

InnoDB 是 MySQL 的默认事务性引擎,它被设计用来处理大量短期事务,短期事务大部分情况是正常提交的,很少会回滚。InnoDB采用 MVCC(多版本并发控制)来支持高并发,并实现四个标准的隔离级别。其默认级别是 REPEATABLE READ(可重复读),并且通过间隙锁策略防止出现幻读的出现。

InnoDB 引擎是基于聚簇索引建立的。聚索簇引对主键查询有很高的性能。

MVCC

可以认为是行级锁的一个变种,但是在很多情况下避免了加锁的操作,因此开销更低。实现思路大体都是非阻塞的读,写操作只锁定必要的行。

  • 每行数据都存在一个版本,每次数据更新时都更新该版本
  • 修改时Copy出当前版本随意修改,每个事务之间无干扰
  • 保存时比较版本号,如果成功(commit),则覆盖原记录;失败则放弃copy(rollback)

就是每行都有版本号,保存时根据版本号决定是否成功,挺像乐观锁的,而 Innodb 的实现方式是:

  • 事务以排他锁的形式修改原始数据
  • 把修改前的数据存放于undo log,通过回滚指针与主数据关联
  • 修改成功(commit)啥都不做,失败则恢复undo log中的数据(rollback)
Read more »

Redis系列:

Redis是一款NoSQL数据库,在大多数项目中作为缓存使用,也可以作为数据库,存储数据。

数据库

Redis服务器将所有数据库都保存在服务器状态 redis.h/redisServer 结构的 db 数组中,db 数组的每个项都是一个 redis.h/redisDb结构,每个 redis 结构代表个数据库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct redisServer {
//...
redisDb *db;//数组,保存服务器中的所有数据库
//...
int dbnum; //服务器数据库数量,默认16个
//...
};
//数据库键空间
typedef struct redisDb {
dict *dict; /* 数据库键空间,保存着数据库中所有键值对 */
dict *expires; /* 过期字典,保存所有过期时间*/
dict *blocking_keys; /* Keys with clients waiting for data (BLPOP)*/
dict *ready_keys; /* Blocked keys that received a PUSH */
dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */
int id; /* Database ID */
long long avg_ttl; /* Average TTL, just for stats */
list *defrag_later; /* List of key names to attempt to defrag one by one, gradually. */
} redisDb;

键空间和用户所见的数据库是直接对应的:

  • 键空间的键也就是数据库的键,每个键都是一个字符串对象。
  • 键空间的值也就是数据库的值,每个值可以是字符串对象、列表对象、哈希表对象、集合对象和有序集合对象中的任意一种 Redis 对象。

过期键删除策略

Read more »