dream

一个菜鸟程序员的成长历程

0%

队列

队列是一种先进先出的数据结构

我们的程序在什么情况下会用到队列呢?异步处理

场景

我们一般写的web程序都是同步执行的,比如前端发送一个登录请求,后端一步一步的处理,查询用户,判断密码等等,返回登陆成功或者错误信息,前端阻塞等到后端返回后进行下一步处理。

那么这种程序有一个什么问题呢,首先,前后端建立的http连接是有超时时间的,当后端处理请求时间过长会返回超时错误。

就算没有超时的限制,对于用户体验来讲,当你的程序响应很慢,那么用户就会觉得,这什么玩意,真垃圾!!!

导出场景

基于这些原因,我们可以需要快速的处理用户请求。像导出大文件的时候,没办法很快的给用户响应怎么办呢,我们可以用异步的方式处理,先给用户返回正在导出,或者导出成功。

这个时候我们后台程序真的导出了嘛?没有,我们可以将这个导出请求放入一个队列中,等待另外一个处理程序将队列中的数据取出进行处理,这个处理程序一直监听队列,如果发现队列有消息,就去取出来进行处理。在处理程序中可以根据数据类型的不同,把它送到具体的处理类中,比如导出数据,处理程序会分发给导出类进行处理,由导出类处理完成后,返回处理完成。

阅读全文 »

布隆过滤器

上一节提到了缓存穿透的问题,如果查询不存在的值怎么办,布隆过滤器可以完美解决这个问题。

当查询的时候,我们只需要确定这个值不存在,那我们就不用再查询了,也就减少了数据库,缓存的压力,减少了服务器压力,避免了一些攻击。

布隆过滤器是个什么东西呢,它是由一串二进制组成的串,这个串中,只有01

0代表不存在,1代表存在。

我们用hash算法计算之后,对布隆过滤器的长度进行取余操作,确定这个值应该存在布隆过滤器的哪个位置上。确定之后,将这个位置的值设置为1

例如:

有一个长度为32的布隆过滤器

阅读全文 »

缓存的使用

当数据的读取量非常大的时候,为了缓解数据库的压力,会大量的使用到缓存。

那什么是缓存呢,我觉得是这样的

两种存储介质a,b,只要a比b快,就可以用a来做b的缓存

数据库一般都是存储在磁盘上面,但是磁盘的访问速度比较慢,当我们想快速获取到数据的时候,显然磁盘已经满足不了我们的需求了。

这时候我们一般会用到Redis, Memchached这种把数据存放在内存之中的NoSql数据库,用他们来缓存我们的数据,因为内存中的读取要比磁盘快的多。

那么缓存到底要怎么用呢?是只要把数据放到Redis里面,然后读取就可以了吗?

如果只是这么简单就好了,在缓存的时候我们要考虑几点东西。

缓存既然是在内存中,那么他们能存储的量就不大,那么哪些数据要放在缓存中呢?缓存的命中率应该达到多少呢?

在什么时候写入缓存呢?该怎么读取缓存呢?

怎么防止缓存穿透和缓存雪崩呢?

阅读全文 »

发号器

生成唯一id的需求很多,我们经常会用到,不管是单库单表中的唯一,还是分布式的唯一。

SnowFlake 算法

说一下SnowFlake算法,这个算法是一个生成唯一id的算法。

使用的是一个64位的二进制串,把这个串分成了几个部分。

  • 符号位 占一个位置 0 为正
  • 时间戳位 占41个位置,使用毫秒级时间戳
  • 机器位 占10个位置, 可以支持2的10次方-1个机器使用
  • 序号位 占12个位置, 同一毫秒内可以生成2的12次方-1个id
阅读全文 »

mysql 分库分表

上一篇文章我们介绍了mysql的主从读写分离,这里我们介绍分库分表的应用。

什么是分库分表呢,分就是拆分,也就是将一个数据表(库)拆分成多个。那有什么作用呢,可以分散流量,和主从类似,主从是将读写流量分开,方便扩展,这里是将表(库)分开方便扩展。同时流量分散,比如一张上亿数据的表,那么查询起来肯定很慢,但是要是水平拆分成多张表,每张表的数据量就会很小,查询速度就会变快。

分库分表一般分为两种,一种是水平拆分,一种是垂直拆分。

阅读全文 »

mysql主从读写分离

场景

mysql主从复制的常见使用场景,当我们的读写流量过大的情况下,尤其是读流量过大的情况下,mysql主从读写分离就很有必要了。

我们使用主库写入,读取从库来分离读写流量,而这时候读流量不断增加,那我们只需要扩展从库就可以了。

阅读全文 »

你不知道的 javascript

作用域

作用域了解了 lhs 和 rhs 两种查找方式

  • lhs, 赋值左侧查找,需要找到变量,然后进行赋值,如果没找到,在非严格模式下会创建变量,严格模式会抛出 ReferenceError 异常
  • rhs,非赋值左侧查找,在引用的时候使用这种查找,在作用域里面如果没有查到,会直接抛出 ReferenceError 异常,而如果你查到了,但是操作不合法,比如试图对一个非函数类型的值进行函数调用,或者引用 null 或 undefined 类型的值中的属性,那么会抛出 TypeError 异常

ReferenceError和作用域的判别失败有关,而TypeError则是代表作用域里面找到了,但是对结果的操作是非法或者不合理的

阅读全文 »

竞选流程

etcd内部采用raft协议来实现,所以在etcd里面,节点有3个状态,一开始都是follower节点,然后接收leader的心跳信息,如果接收不到,就进入candidate进入下一轮term发起竞选,等到收到集群多数节点的投票时,该节点就会转变成新的leader节点。leader节点有可能出现故障,导致follower接收不到心跳,这时候就会发生上面的竞选,新的leader产生以后,旧的leader就会变成follower。其实就是有新的leader之后,所有其他节点都会变成follower。

成为leader也是有条件的,比如你的数据完整性,在竞选投票的时候,如果其他节点发现你的数据不完整,是不会给你投票的。

节点损坏

节点可能会因为各种原因损坏,导致无法正常工作。如果是leader节点那么就会导致follower收不到心跳而触发竞选机制,如果是follower节点,那么我们可以将这个节点删除以后在创建新的节点。因为损坏的节点依然会被计算在etcd总节点之中。

etcd采用基于仲裁模型的分布式共识,即(n + 1) / 2成员(多数)必须就提案一致才能提交给集群。因此当有follower损坏的时候,我们需要先删除在创建,而不能先创建在删除。

比如:如果有一个3个成员的集群,有一个成员损坏,那么这个集群仍然可以正常工作,这个时候删除损坏成员,该集群依然可以正常工作,然后添加新节点,这个行为是存在风险的,因为他可能会导致配置错误或无法加入集群,这种情况下,集群依然可以正常工作。而如果正确加入,依然可以正常工作。那我们想一下先增加新成员,如果增加失败,那么该集群总成员数量变成4个,而其中有1个早已损坏,还有一个刚添加的同样算是损坏,这将会使仲裁失效,所以默认情况下,etcd会拒绝这种成员的添加。

阅读全文 »