往期文章一览

分布式会话与单点登录SSO系统CAS,包含完整示例代码实现

【7W字长文】使用LVS+Keepalived实现Nginx高可用,一文搞懂Nginx

主从复制高可用Redis集群

分布式架构介绍

什么是分布式架构

随着越来越多的人参与到互联网的浪潮来,曾经的单体应用架构越来越无法满足需求,所以,分布式集群架构出现,也因此,分布式搭建开发成为了Web开发者必掌握的技能之一。那什么是分布式呢?怎么实现分布式以及怎么处理分布式带来的问题呢?本系列文章就来源于对分布式各组件系统的学习总结,包含但不限于Zookeeper、Dubbo、消息队列(ActiveMQ、Kafka、RabbitMQ)、NoSql(Redis、MongoDB)、Nginx、分库分表MyCat、Netty等内容。

简单的说,“分工协作,专人做专事”就是分布式的概念。不同的功能模块分散部署在不同的服务器,每个子系统负责一个或多个不同的业务模块,服务之间可以相互交互和通信。

分布式系统设计对用户是透明的,用户只关心请求是否能返回相应的结果而已,和集群对用户透明的概念类似。同时,分布式架构中每个服务也可以做集群,可以发展为集群分布式系统架构,而且一个服务的集群对于其他服务来说也是透明的。微服务架构是属于分布式架构的一种,微服务架构是分布式架构的一个子集。

  • 集群:你们公司业务增长的非常快,老板发现你一个后端忙不过来了,就又招了几个后端开发来协助你,这就是后端集群;再往后,发现前端也忙不过来了,又配备几个前端,就是前端集群。所以也不难看出,将应用拆分后,你可以有针对性地扩展单个服务,做成集群,这就是分布式的好处之一。
  • 节点:这个也非常好理解,一个服务就是一个节点,比如你就是后端集群中的一个节点,而集群本身也可以看成是整个应用的一个集群节点。
  • 副本:副本就是为服务和数据提供的冗余,保证高可用。
  • 中间件:为开发者提供便利,屏蔽复杂的底层的一类框架组件。如服务管理通信、序列化、负载均衡等组件。

单体架构和分布式架构举例描述

举例来说,一个工人造汽车时,从左到右每个环节都是他来处理,最后得到一台整车。这时,服务的性能顶点就很低,因为一个人的能力是有限的。

当然我们也可以多请几个工人,多线进行,形成一个相当于服务集群的效果,当然这个是把整个服务的所有功能都进行了集群。但是又出现一个问题,比如说装底盘比较简单,几分钟就完成了,而装轮子比较难,几天都完成不了。那么影响汽车建造完成的瓶颈就在轮子上,我把整个流程复制一份,再请一个工人来做,成本提高了,但是效率却并没有提升这么大。因为装底盘本来就简单,我一个人就可以跟上生产的速度,我没必要两个人都要去装底盘。

为了解决这个问题,首先我们把人员分来,每个人只做自己擅长的事情,就像是流水线。这样学习时间会缩短,熟练之后效率也提高的快,这就形成了一个基本的分布式架构。

装轮子比较困难,一个人装需要几天时间,我可以多分配几个人一起装,这样可以提高这个步骤的安装时间,而其他步骤比较简单的,就保持一个人就行了。定向优化某一个服务,提高它的性能瓶颈,这样可以尽量缩短每个服务处理的时间差,成本也可以大大减少,这就形成了分布式集群架构。

分布式架构的优点

  1. 业务解耦:解耦之后方便性能优化。
  2. 系统模块化,可重用化:发布时也不用全部模块一起发布,只需要发布更新的模块就行了。
  3. 提升系统并发量:单体架构的并发量是有限的,而分布式架构可以集群某一个可承载并发量比较低的模块从而提升整体架构的并发量上限。
  4. 优化运维部署效率:迭代发布时,只需要根据模块发布,包比较轻巧,单体架构打包往往比较庞大。

分布式架构的缺点

  1. 架构比较复杂:功能多了,模块多,服务器也会更多,架构就更加复杂了
  2. 部署多个子系统复杂:当同时修改多个模块时,部署则需要同时更新多个服务器上面的应用
  3. 系统之间通信耗时:服务之间调用会有时间的损耗,这是不可避免的。
  4. 新人融入团队缓慢:架构复杂时,新人上手难度会变高
  5. 调试复杂:调用链路比较长的话,debug时往往需要同时启多个服务,打印日志也需要在多个服务中查看。

基本设计原则

  1. 异步解构:模块拆分之后,模块与模块之间的通信会有异步和同步之分。能使用异步尽量使用异步,不到万不得已不要使用同步,因为异步的效率往往要比同步高很多,异步解耦需要涉及到消息队列。
  2. 幂等一致性:用户的请求可能需要经过多个子系统,不管是查询或者增删改,多次操作或者重复操作数据的一致性是需要保证的。主要针对于增加和修改操作,因为查询多查几次结果都是一致的,删除删掉一次数据就没有了,多删几次也不会删掉别的数据,而增加假如没有处理好会增加很多条重复数据,会使应用出现问题。
  3. 拆分原则:可以根据业务来拆,比如说可以拆分成订单系统、文件系统、门户系统等;也可以根据系统功能来拆分比如把文件系统可以拆分成上传文件子系统、下载文件子系统等。
  4. 融合分布式中间件:比如Redis可以作为缓存,Zookeeper可以作为协调,MQ可以作为消息队列等,这些我们都可以把它融入到我们的系统中去。
  5. 容错高可用:每个服务单独部署都会容易产生单点故障,这是我们可以使用集群的方案来应对单点故障,集群和分布式技术是相辅相成的

分布式架构需要使用到的技术

  1. 分布式缓存中间件Redis
  2. 分布式会话以及单点登录
  3. 分布式搜索引擎Elasticsearch
  4. 分布式文件系统
  5. 分布式消息队列
  6. 分布式锁
  7. 数据库读写分离以及分库分表
  8. 数据库表全局唯一主键id设计
  9. 分布式事务以及数据一致性
  10. 接口幂等设计以及分布式限流

分布式缓存和技术选型

什么是Redis

Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。

Redis的出现,很大程度补偿了Memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。

它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。

和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,Redis支持各种不同方式的排序。与Memcached一样,为了保证效率,数据都是缓存在内存中。

区别的是Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。

Redis的官网地址,非常好记,是redis.io。(域名后缀io属于国家域名,是british Indian Ocean territory,即英属印度洋领地)

特性和特点

Redis是现在最受欢迎的NoSQL数据库之一,Redis是一个使用ANSI C编写的开源、包含多种数据结构、支持网络、基于内存、可选持久性的键值对存储数据库,其具备如下特性:

  • 基于内存运行,性能高效
  • 支持分布式,理论上可以无限扩展
  • key-value存储系统
  • 开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API

相比于其他数据库类型,Redis具备的特点是:

  • C/S通讯模型
  • 单进程单线程模型
  • 丰富的数据类型
  • 操作具有原子性
  • 持久化
  • 高并发读写
  • 支持lua脚本

参考链接:

Redis是什么?看这一篇就够了

为什么要引入Redis

在Web应用发展的初期,那时关系型数据库受到了较为广泛的关注和应用,原因是因为那时候Web站点基本上访问和并发不高、交互也较少。而在后来,随着访问量的提升,使用关系型数据库的Web站点多多少少都开始在性能上出现了一些瓶颈,而瓶颈的源头一般是在磁盘的I/O上。而随着互联网技术的进一步发展,各种类型的应用层出不穷,这导致在当今云计算、大数据盛行的时代,对性能有了更多的需求,主要体现在以下四个方面:

  1. 低延迟的读写速度:应用快速地反应能极大地提升用户的满意度
  2. 支撑海量的数据和流量:对于搜索这样大型应用而言,需要利用PB级别的数据和能应对百万级的流量
  3. 大规模集群的管理:系统管理员希望分布式应用能更简单的部署和管理
  4. 庞大运营成本的考量:IT部门希望在硬件成本、软件成本和人力成本能够有大幅度地降低

为了克服这一问题,NoSQL应运而生,它同时具备了高性能、可扩展性强、高可用等优点,受到广泛开发人员和仓库管理人员的青睐。

现有架构分析

  1. 浏览器访问时,请求先到LVS,使用Keepalived让两台LVS达成一个主备关系或者双主热备关系
  2. LVS的之后是Nginx集群,LVS是四层负载均衡,使用DR模式使请求通过LVS,而响应直接由应用响应到浏览器
  3. 每个Nginx集群的每一个节点都使用了upstream模块,配置了tomcat集群
  4. 因为每个应用服务是完全相同的,所以他们的都会连接到同一个数据库,现在应用的性能瓶颈就在应用到数据库之间
  5. 在应用的时,对于数据库来说当中有一个二八原则,请求中百分之八十都是读请求,写请求远远少于读请求

举个例子,假如系统中有2千万用户信息,用户信息基本固定,一旦录入很少变动,那么你每次加载所有用户信息时,如果都要请求数据库,数据库编译并执行你的查询语句,这样效率就会低下很多,针对这种信息不经常变动并且数据量较大的情况,通常做法,就是把他加入缓存,每次取数前先去判断,如果缓存不为空,那么就从缓存取值,如果为空,再去请求数据库,并将数据加入缓存,这样大大提高系统访问效率。

其次,假如有一个明星的负面新闻被曝光在微博上了,这时会有几千万上亿的请求会访问到它。对于这种高流量的热点新闻,我们也可以加入缓存,减缓数据库压力,是数据库不会被上亿的流量冲垮。

所以,我们可以使用Redis缓存把应用服务和数据库分隔开,把一些热点数据和不经常变动的数据放到缓存中,让上亿的请求访问到Redis,而不会直接接触数据库,从而达到保护数据库的效果。相当于提高了数据库的读取这类型数据的性能,也就是提高了应用服务的性能和吞吐量,也可以承载更多的并发。

Redis的作用

动物园中有各种动物,当游客来到动物园中,她想要知道大熊猫有多少只。她去询问管理员时,管理员进去动物园中数了数大熊猫的数量,返回到原来的地方告诉游客她想要知道的信息。这时若客流量突然变大时,管理员对于每一个人的问题都要去动物园中寻找,他就会非常累。

管理员灵机一动想到了一个方法,他每次去动物园中寻找时,把问题和问题对应的结果写到一个账本上。久而久之,账本上记录的问题和数据越来越多。

当他遇到有人问到之前记录过的一个问题时,他就会直接把账本上的问题答案回答给游客,就不用再一次进去动物园中了。这时,他能接待的客流量就增多了。

这时又会出现一个问题,当动物园中动物的数据发生变化之后,账本和真实数据就对应不上了。这就要靠动物园中的维护人员来保证数据的一致性了,当动物园中动物数据发生变化之后,维护人员要及时修改账本的数据,使其数据和真实数据保持一致。

而账本就相当于我们架构中的Redis,管理员和动物园相当于数据库,这样我们应用的并发量和吞吐量也就提高了,当原有数据发生变化时(新增或修改),要及时更新Redis中缓存的数据,保证数据一致性。

什么是NoSql

NoSQL(NoSQL = Not Only SQL ),意即"不仅仅是SQL"。

  • 平时我们使用的最多的数据库MySql、postgreSql等等都是关系型数据库,NoSql则是非关系型数据库
  • 对于关系型数据库来说,是需要把数据存储到库、表、行、字段里,查询的时候根据条件一行一行地去匹配,当量非常大的时候就很耗费时间和资源,尤其是数据是需要从磁盘里去检索
  • NoSQL数据库存储原理非常简单(典型的数据类型为k-v),不存在繁杂的关系链,比如mysql查询的时候,需要找到对应的库、表(通常是多个表)以及字段
  • NoSQL数据可以存储在内存里,查询速度非常快
  • NoSQL在性能表现上虽然能优于关系型数据库,但是它并不能完全替代关系型数据库
  • NoSQL因为没有复杂的数据结构,扩展非常容易,支持分布式

传统项目都是使用关系型数据库,访问量也不是很大,任何请求过来直接查询数据库也不会造成什么影响。当今互联网中数据量越来越大,请求数和并发要求越来越高,而传统的纯数据库架构设计慢慢的不能满足我们的需求。普通的关系型数据库不再适合把超大量的数据提供出去做并发型的查询(用户信息,地理信息,购物信息等)。数据库单表的性能是有限的,数据库做的好优化的好的话单表数据量能到达400w-600w的样子,而一般一点的最多只能到300w-400w,就会对应用的性能造成很大的影响。

一旦数据量达到300w时,数据库管理员(DBA)就要及时准备数据库的优化方案,从而的对数据库进行优化。数据库的数据量庞大之后,关系型数据库也不适合对数据进行深挖(数据挖掘、大数据分析等)。这时使用NoSql就是顺势而为,NoSql水平(横向)扩展非常方便高效。Redis的数据结构是key-value的这种结构,存储形式是非常简单的,所以扩展起来就非常容易,而且由于是键值对这种形式,增加或者删除缓存中的数据会非常高效。数据库中数据量到达上百万的话,数据库中增加和删除数据性能会非常差,若是针对字段的新增或者删除其对性能的影响更是灾难性的,对于整体的数据会有非常大的影响。

对于Redis来说,它的读取性能是非常高的,每秒能达到十万次,远远大于传统关系型数据库。还能搭建集群,而且非常容易。可以存储数据,也可以对于缓存的数据进行持久化(不同的NoSql,对于持久化的支持情况不同)。

NoSql的分类

键值对数据库

相关产品:Redis、Riak、SimpleDB、Chordless、Scalaris、Memcached

应用:内容缓存

优点:扩展性好、灵活性好、大量写操作时性能高

缺点:无法存储结构化信息、条件查询效率较低

使用者:百度云(Redis)、GitHub(Riak)、BestBuy(Riak)、Twitter(Ridis和Memcached)

列存储数据库

相关产品:BigTable、HBase、Cassandra、HadoopDB、GreenPlum、PNUTS

应用:分布式数据存储与管理

优点:查找速度快、可扩展性强、容易进行分布式扩展、复杂性低

使用者:Ebay(Cassandra)、Instagram(Cassandra)、NASA(Cassandra)、Facebook(HBase)

文档型数据库

相关产品:MongoDB、CouchDB、ThruDB、CloudKit、Perservere、Jackrabbit

应用:存储、索引并管理面向文档的数据或者类似的半结构化数据

优点:性能好、灵活性高、复杂性低、数据结构灵活

缺点:缺乏统一的查询语言

使用者:百度云数据库(MongoDB)、SAP(MongoDB)

图形数据库

相关产品:Neo4J、OrientDB、InfoGrid、GraphDB

应用:大量复杂、互连接、低结构化的图结构场合,如社交网络、推荐系统等

优点:灵活性高、支持复杂的图形算法、可用于构建复杂的关系图谱

缺点:复杂性高、只能支持一定的数据规模

使用者:Adobe(Neo4J)、Cisco(Neo4J)、T-Mobile(Neo4J)

参考链接:

NoSQL的四大类型

总结:Redis、Memcached、MongoDB是国内使用的最多的数据库,假如一个项目没有使用到任何一个NoSql则可以断定这是一个非常传统的项目

什么是分布式缓存

在高并发的分布式的系统中,缓存是必不可少的一部分。没有缓存对系统的加速和阻挡大量的请求直接落到系统的底层,系统是很难撑住高并发的冲击,所以分布式系统中缓存的设计是很重要的一环。

在高并发的场景下,通过分布式缓存可以提高数据的读取数据,相应的应用的性能和吞吐量就提高了。这里只针对读操作,读取数据时尽量在缓存中读取,可以降低数据库对服务器性能的开支,降低服务器的压力,而写操作时才把数据直接写到数据库,这里遵循二八原则(百分之八十都是读操作)。Redis是基于内存的,读写性能远远高于磁盘存储的数据库。一般情况下,尽量让大部分查询请求去命中缓存,少量的请求根据需要直接操作数据库。在分布式系统中,分布式缓存中的数据可以被所有服务访问到,可以很轻松的实现服务之间数据的共享。

使用缓存我们得到以下收益

  • 加速读写。因为缓存通常是全内存的,比如Redis、Memcache。对内存的直接读写会比传统的存储层如MySQL,性能好很多。举个例子:同等配置单机Redis QPS可轻松上万,MySQL则只有几千。加速读写之后,响应时间加快,相比之下系统的用户体验能得到更好的提升。

  • 降低后端的负载。缓存一些复杂计算或者耗时得出的结果可以降低后端系统对CPU、IO、线程这些资源的需求,让系统运行在一个相对资源健康的环境。

但随之以来也有一些成本

  • 数据不一致性:缓存层与存储层的数据存在着一定时间窗口一致,时间窗口与缓存的过期时间更新策略有关。
  • 代码维护成本:加入缓存后,需要同时处理缓存层和存储层的逻辑,增加了开发者维护代码的成本。
  • 运维成本:引入缓存层,比如Redis。为保证高可用,需要做主从,高并发需要做集群。

综合起来,只要收益大于成本,我们就可以采用缓存。

参考链接:

深入理解分布式缓存设计

缓存方案的对比

Ehcache

Ehcache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认CacheProvider。Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储、缓存加载器、缓存扩展、缓存异常处理程序、一个gzip缓存servlet过滤器、支持REST和SOAP API等特点。

Spring 提供了对缓存功能的抽象:即允许绑定不同的缓存解决方案(如Ehcache),但本身不直接提供缓存功能的实现。它支持注解方式使用缓存,非常方便。

特性
  • 快速、简单
  • 多种缓存策略
  • 缓存数据有两级:内存和磁盘,因此无需担心容量问题
  • 缓存数据会在虚拟机重启的过程中写入磁盘
  • 可以通过RMI、可插入API等方式进行分布式缓存
  • 具有缓存和缓存管理器的侦听接口
  • 支持缓存管理器实例,以及一个实例的多个缓存区域
  • 提供Hibernate的缓存实现
优点

  1. 基于Java开发:对于Java项目的整合,其代码的健壮性比较好
  2. 基于JVM缓存:在JVM中使用的话,速度比较快,性能也会更高
  3. 简单、轻巧、方便:整合起来非常容易,很多框架都整合了Ehchache,例如:hibernate
缺点

  1. 集群不支持:不支持缓存共享,对于集群的实现非常复杂,维护起来也非常不方便
  2. 分布式不支持:Ehchache更加适合于单应用以及快速开发
集成

可以单独使用,一般在第三方库中被用到的比较多(如mybatis、shiro等)Ehcache 对分布式支持不够好,多个节点不能同步,通常和redis一块使用

灵活性

Ehcache具备对象api接口和可序列化api接口

不能序列化的对象可以使用出磁盘存储外Ehcache的所有功能

支持基于Cache和基于Element的过期策略,每个Cache的存活时间都是可以设置和控制的。

提供了LRU、LFU和FIFO缓存淘汰算法,Ehcache 1.2引入了最少使用和先进先出缓存淘汰算法,构成了完整的缓存淘汰算法。

提供内存和磁盘存储,Ehcache和大多数缓存解决方案一样,提供高性能的内存和磁盘存储。

动态、运行时缓存配置,存活时间、空闲时间、内存和磁盘存放缓存的最大数目都是可以在运行时修改的。

应用持久化

在jvm重启后,持久化到磁盘的存储可以复原数据

Ehache是第一个引入缓存数据持久化存储的开源java缓存框架,缓存的数据可以在机器重启后从磁盘上重新获得

根据需要将缓存刷到磁盘。将缓存条目刷到磁盘的操作可以通过cache.fiush方法执行,这大大方便了Ehcache的使用

Ehcache和Redis 比较
  • Ehcache直接在jvm虚拟机中缓存,速度快,效率高;但是缓存共享麻烦,集群分布式应用不方便。
  • Redis是通过socket访问到缓存服务,效率比Ecache低,比数据库要快很多,处理集群和分布式缓存方便,有成熟的方案。如果是单个应用或者对缓存访问要求很高的应用,用Ehcache。如果是大型系统,存在缓存共享、分布式部署、缓存内容很大的,建议用Redis。

参考链接:

EhCache

ehcache memcache redis 三大缓存男高音

Memcache

Memcache是一个自由、源码开放、高性能、分布式的分布式内存对象缓存系统,用于动态Web应用以减轻数据库的负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高了网站访问的速度。Memcache是一个存储键值对的HashMap,在内存中对任意的数据(比如字符串、对象等)所使用的key-value存储,数据可以来自数据库调用、API调用,或者页面渲染的结果。Memcache设计理念就是小而强大,它简单的设计促进了快速部署、易于开发并解决面对大规模的数据缓存的许多难题,而所开放的API使得Memcache能用于Java、C/C++/C#、Perl、Python、PHP、Ruby等大部分流行的程序语言。

Memcache通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。简单的说就是将数据调用到内存中,然后从内存中读取,从而大大提高读取速度。Memcached是以守护程序(监听)方式运行于一个或多个服务器中,随时会接收客户端的连接和操作。

另外,说一下Memcache和Memcached的区别:

  1. Memcache是项目的名称

  2. Memcached是Memcache服务器端可以执行文件的名称

特性和限制
  • 在 Memcached中可以保存的item数据量是没有限制的,只要内存足够 。
  • Memcached单进程在32位系统中最大使用内存为2G,若在64位系统则没有限制,这是由于32位系统限制单进程最多可使用2G内存,要使用更多内存,可以分多个端口开启多个Memcached进程 。
  • 最大30天的数据过期时间,设置为永久的也会在这个时间过期,常量REALTIME_MAXDELTA 60 * 60 * 24 * 30控制
  • 最大键长为250字节,大于该长度无法存储,常量KEY_MAX_LENGTH 250控制
  • 单个item最大数据是1MB,超过1MB数据不予存储,常量POWER_BLOCK 1048576进行控制,它是默认的slab大小
  • Memcache服务端是不安全的,比如已知某个Memcache节点,可以直接telnet过去,并通过flush_all让已经存在的键值对立即失效
  • Memcache的高性能源自于两阶段哈希结构:第一阶段在客户端,通过Hash算法根据Key值算出一个节点;第二阶段在服务端,通过一个内部的Hash算法,查找真正的item并返回给客户端。从实现的角度看,Memcache是一个非阻塞的、基于事件的服务器程序
  • 最大同时连接数是200,通过 conn_init()中的freetotal进行控制,最大软连接数是1024,通过 settings.maxconns=1024 进行控制
  • 跟空间占用相关的参数:settings.factor=1.25, settings.chunk_size=48, 影响slab的数据占用和步进方式
  • memcached是一种无阻塞的socket通信方式服务,基于libevent库,由于无阻塞通信,对内存读写速度非常之快。
  • memcached分服务器端和客户端,可以配置多个服务器端和客户端,应用于分布式的服务非常广泛。
  • memcached作为小规模的数据分布式平台是十分有效果的。
  • memcached是键值一一对应,key默认最大不能超过128个字 节,value默认大小是1M,也就是一个slabs,如果要存2M的值(连续的),不能用两个slabs,因为两个slabs不是连续的,无法在内存中 存储,故需要修改slabs的大小,多个key和value进行存储时,即使这个slabs没有利用完,那么也不会存放别的数据。
  • memcached已经可以支持C/C++、Perl、PHP、Python、Ruby、Java、C#、Postgres、Chicken Scheme、Lua、MySQL和Protocol等语言客户端

参考链接:

Memcache的 简介

MemCache详细解读

Memcached简介

优点

  1. 部分容灾:假设只用一台Memcache,如果这台Memcache服务器挂掉了,那么请求将不断的冲击数据库,这样有可能搞死数据库,从而引发”雪崩“。如果使用多台Memcache服务器,由于Memcache使用一致性哈希算法,万一其中一台挂掉了,部分请求还是可以在Memcache中命中,为修复系统赢得一些时间。
  2. 横向扩展简单:一台Memcache服务器的容量毕竟有限,可以使用多台Memcache服务器,增加缓存容量。
  3. 均衡请求:使用多台Memcache服务器,可以均衡请求,避免所有请求都冲进一台Memcache服务器,导致服务器挂掉。
  4. 多核运行:Memcache 可以利用多核优势,单实例吞吐量极高,可以达到几十万 QPS(取决于 key、value 的字节大小以及服务器硬件性能,日常环境中 QPS 高峰大约在 4-6w 左右)。适用于最大程度扛量。
  5. 支持直接配置为 session handle。
缺点

  1. 只支持简单的 key/value 数据结构,不像 Redis 可以支持丰富的数据类型。

  2. 无法进行持久化,数据不能备份,只能用于缓存使用,且重启后数据全部丢失。

  3. 无法进行数据同步,不能将Memcache中的数据迁移到其他Memcache实例中。

  4. Memcached 内存分配采用 Slab Allocation 机制管理内存,value 大小分布差异较大时会造成内存利用率降低,并引发低利用率时依然出现踢出等问题。需要用户注重 value 设计。

Memcache和Redis比较
  1. 持久化能力:Redis支持持久化,Memcache也支持但一般不做持久化(重启丢失数据)
  2. 数据类型支持:Redis类型较多(5种数据类型,string、list、hash、set、sorted set),Memcache只能是字符串
  3. 线程模型:Redis是单线程+多路IO复用,虽然没有锁冲突,但很难利用多核特性提升整体吞吐量。Memcache是多线程+锁的方式,主线程监听,work子线程接收请求,执行读写,有锁冲突。;
  4. 数据库特征:Redis不是所有的数据都存储在内存,在很多方面具备数据库的特征,Memcache只是简单的kv缓存;相当于Memcache更像是redis在功能上的一个子集。
  5. 高可用支持:高可用(redis原生支持高可用功能,可以实现主从复制,哨兵模式,redis集群模式,而Memcache要实现高可用,需要进行二次开发,例如客户端的双读双写,或者服务端的集群同步)(延伸:虽然数据类型单一,但是Memcache的内存管理机制导致无碎片,这让Memcache工作更加稳定,而redis本身也考虑到自己功能复杂,会产生碎片,并且容易崩溃,所以支持高可用)
  6. 内容大小比较:Redis存储的内容比较大(Memcache的value存储最大是1M,如果存储value很大,只能选择redis)
  7. 内存分配:memchache使用预分配内存池的方式管理内存,能够省区内存分配的时间,这个节省的时间在数据量很大的时候还是很可观的。而redis则是临时申请空间,可能导致碎片。Redis和Memcache在写入性能上面差别不大的,读取性能上面尤其是批量读取性能上面Memcache更强的。

参考链接:

Redis 和 Memcache 相比较优缺点的不同区别是什么

Redis与Memcache区别最全整理

Memcache 持久性分布式数据库MemcacheDB

Redis,Memcache该如何选择?

Redis和Memcache区别,优缺点对比

redis和memcached的区别(总结)

Redis

简单来说 Redis 就是一个用C语言写的数据库,不过与传统数据库不同的是 Redis 的数据是存在内存中的,所以读写速度非常快,因此 Redis 被广泛应用于缓存方向。另外,Redis 也经常用来做分布式锁。Redis 提供了多种数据类型来支持不同的业务场景。除此之外,Redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。

Redis是一个开源的,先进的key-value持久化产品。它通常被称为数据结构服务器,它的值可以是字符串(String)、哈希(Map)、列表(List)、集合(Sets)和有序集合(Sorted sets)等类型。可以在这些类型上面做一些原子操作,如:字符串追加、增加Hash里面的值、添加元素到列表、计算集合的交集,并集和差集;或者区有序集合中排名最高的成员。为了取得好的性能,Redis是一个内存型数据库。不限于此,Redis也可以把数据持久化到磁盘中,或者把数据操作指令追加了一个日志文件,把它用于持久化。也可以用Redis容易的搭建master-slave架构用于数据复制。其它让它像缓存的特性包括,简单的check-and-set机制,pub/sub和配置设置。Redis可以用大部分程序语言来操作:C、C++、C#、Java、Node.js、php、ruby等等。

特性
  1. 速度快

    正常情况下,Redis执行命令的速度非常快,官方给出的数字是读写性能可以达到10万/秒,当然这也取决于机器的性能,但这里先不讨论机器性能上的差异,只分析一下是什么造就了Redis除此之快的速度,可以大致归纳为以下三点:

    • Redis的所有数据都是存放在内存中的,所以把数据放在内存中是Redis速度快的最主要原因。
    • Redis是用C语言实现的,一般来说C语言实现的程序“距离”操作系统更近,执行速度相对会更快。
    • Redis使用了单线程架构,预防了多线程可能产生的竞争问题。
  2. 基于键值对的数据结构服务器

    几乎所有的编程语言都提供了类似字典的功能,例如Java里的map、Python里的dict,类似于这种组织数据的方式叫作基于键值的方式,与很多键值对数据库不同的是,Redis中的值不仅可以是字符串,而且还可以是具体的数据结构,这样不仅能便于在许多应用场景的开发,同时也能够提高开发效率。Redis的全称是REmote Dictionary Server,它主要提供了5种数据结构:字符串、哈希、列表、集合、有序集合。

  3. 丰富的功能

    除了5种数据结构,Redis还提供了许多额外的功能:

    • 提供了键过期功能,可以用来实现缓存。
    • 提供了发布订阅功能,可以用来实现消息系统。
    • 支持Lua脚本功能,可以利用Lua创造出新的Redis命令。
    • 提供了简单的事务功能,能在一定程度上保证事务特性。
    • 提供了流水线(Pipeline)功能,这样客户端能将一批命令一次性传到Redis,减少了网络的开销。
  4. 简单稳定

    Redis的简单主要表现在三个方面。

    • Redis的源码很少。
    • Redis使用单线程模型,这样不仅使得Redis服务端处理模型变得简单,而且也使得客户端开发变得简单。
    • Redis不需要依赖于操作系统中的类库(例如Memcache需要依赖libevent这样的系统类库),Redis自己实现了事件处理的相关功能。
    • Redis虽然很简单,但是不代表它不稳定。维护的上千个Redis为例,没有出现过因为Redis自身bug而宕掉的情况。
  5. 客户端语言多

    Redis提供了简单的TCP通信协议,很多编程语言可以很方便地接入到Redis,并且由于Redis受到社区和各大公司的广泛认可,所以支持Redis的客户端语言也非常多,几乎涵盖了主流的编程语言,例如Java、PHP、Python、C、C++、Nodejs等。

  6. 持久化

    通常看,将数据放在内存中是不安全的,一旦发生断电或者机器故障,重要的数据可能就会丢失,因此Redis提供了两种持久化方式:RDB和AOF,即可以用两种策略将内存的数据保存到硬盘中(如图所示)这样就保证了数据的可持久性。

  7. 主从复制

    Redis提供了复制功能,实现了多个相同数据的Redis副本(如图所示),复制功能是分布式Redis的基础。

  8. 高可用和分布式

    Redis从2.8版本正式提供了高可用实现Redis Sentinel,它能够保证Redis节点的故障发现和故障自动转移。Redis从3.0版本正式提供了分布式实现Redis Cluster,它是Redis真正的分布式实现,提供了高可用、读写和容量的扩展性。

参考链接:

redis的八大特性

优点

  1. 支持多种数据类型:包括set,zset,list,hash,string这五种数据类型,操作非常方便。比如,如果你在做好友系统,查看自己的好友关系,如果采用其他的key-value系统,则必须把对应的好友拼接成字符串,然后在提取好友时,再把value进行解析,而Redis则相对简单,直接支持list的存储(采用双向链表或者压缩链表的存储方式)。
  2. 持久化存储:作为一个内存数据库,最担心的,就是万一机器死机,数据会消失掉。redi使用rdb和aof做数据的持久化存储。主从数据同时,生成rdb文件,并利用缓冲区添加新的数据更新操作做对应的同步。
  3. 丰富的特性:pub/sub,key过期策略,事务,支持多个DB等。
  4. 性能很好:由于是全内存操作,所以读写性能很好,可以达到10w/s的频率。公司有项目使用Redis,目前的访问频率是80w/s,通过适当的部署,线上运行一切ok。
缺点

  1. 由于是内存数据库,所以,单台机器,存储的数据量,跟机器本身的内存大小。虽然Redis本身有key过期策略,但是还是需要提前预估和节约内存。如果内存增长过快,需要定期删除数据。
  2. 如果进行完整重同步,由于需要生成rdb文件,并进行传输,会占用主机的CPU,并会消耗现网的带宽。不过Redis2.8版本,已经有部分重同步的功能,但是还是有可能有完整重同步的。比如,新上线的备机。
  3. 修改配置文件,进行重启,将硬盘中的数据加载进内存,时间比较久。在这个过程中,Redis不能提供服务。
相关问题
  1. 数据库和缓存双写一致性问题:一致性问题是分布式常见问题,还可以再分为最终一致性和强一致性。数据库和缓存双写,就必然会存在不一致的问题。就是如果对数据有强一致性要求,不能放缓存。我们所做的一切,只能保证最终一致性。另外,我们所做的方案其实从根本上来说,只能说降低不一致发生的概率,无法完全避免。因此,有强一致性要求的数据,不能放缓存。

  2. 缓存穿透:即黑客故意去请求缓存中不存在的数据,导致所有的请求都怼到数据库上,从而数据库连接异常。解决方案:

    • 利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试
    • 采用异步更新策略,无论key是否取到值,都直接返回。value值中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存。需要做缓存预热(项目启动前,先加载缓存)操作。
    • 提供一个能迅速判断请求是否有效的拦截机制,比如,利用布隆过滤器,内部维护一系列合法有效的key。迅速判断出,请求所携带的Key是否合法有效。如果不合法,则直接返回。
  3. 缓存雪崩:即缓存同一时间大面积的失效,这个时候又来了一波请求,结果请求都怼到数据库上,从而导致数据库连接异常。解决方案:

    • 给缓存的失效时间,加上一个随机值,避免集体失效。
    • 使用互斥锁,但是该方案吞吐量明显下降了。
    • 双缓存。我们有两个缓存,缓存A和缓存B。缓存A的失效时间为20分钟,缓存B不设失效时间。自己做缓存预热操作。然后细分以下几个小点
      • 从缓存A读数据库,有则直接返回
      • A没有数据,直接从B读数据,直接返回,并且异步启动一个更新线程。
      • 更新线程同时更新缓存A和缓存B。
  4. 缓存的并发竞争:同时有多个子系统去set一个key。

    • 如果对这个key操作,不要求顺序:这种情况下,准备一个分布式锁,大家去抢锁,抢到锁就做set操作即可,比较简单。

    • 如果对这个key操作,要求顺序:(假设有一个key1,系统A需要将key1设置为valueA,系统B需要将key1设置为valueB,系统C需要将key1设置为valueC)期望按照key1的value值按照 valueA–>valueB–>valueC的顺序变化。这种时候我们在数据写入数据库的时候,需要保存一个时间戳。假设时间戳如下:

      • 系统A key 1 {valueA 3:00}
      • 系统B key 1 {valueB 3:05}
      • 系统C key 1 {valueC 3:10}

      那么,假设这会系统B先抢到锁,将key1设置为{valueB 3:05}。接下来系统A抢到锁,发现自己的valueA的时间戳早于缓存中的时间戳,那就不做set操作了。以此类推。

      其他方法,比如利用队列,将set方法变成串行访问也可以。总之,灵活变通。

  5. Redis的过期策略以及内存淘汰机制:Redis采用的是定期删除+惰性删除策略。

    • 为什么不用定时删除策略?

      定时删除,用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。在大并发请求下,CPU要将时间应用在处理请求,而不是删除key,因此没有采用这一策略。

    • 定期删除+惰性删除是如何工作的呢?

      定期删除,Redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,Redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms,全部key进行检查,Redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。于是,惰性删除派上用场。也就是说在你获取某个key的时候,Redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。

    • 采用定期删除+惰性删除就没其他问题了么?

      不是的,如果定期删除没删除key。然后你也没即时去请求key,也就是说惰性删除也没生效。这样,Redis的内存会越来越高。那么就应该采用内存淘汰机制。

      在redis.conf中有一行配置:

      # maxmemory-policy volatile-lru

      该配置就是配内存淘汰策略的

      • noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。应该没人用吧。
      • allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。推荐使用,目前项目在用这种。
      • allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。应该也没人用吧,你不删最少使用Key,去随机删。
      • volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。这种情况一般是把Redis既当缓存,又做持久化存储的时候才用。不推荐
      • volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。依然不推荐
      • volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。不推荐
      • ps:如果没有设置 expire 的key, 不满足先决条件(prerequisites); 那么 volatile-lru, volatile-random 和 volatile-ttl 策略的行为, 和 noeviction(不删除) 基本上一致。

参考链接:

Redis 优缺点

redis的优点和缺点

Redis的使用

Redis的安装和配置

  1. 打开官网:https://redis.io (中文官网:http://www.redis.cn)点击下载最新版本的Redis

  2. 上传到Linux服务器

  3. 解压安装包

    tar -zxvf redis.xxxx.tar.gz

  4. 进入解压缩之后的文件夹,可以发现其中有一个Makefile文件,因此安装方式和Nginx类似

  5. 因为是C语言编写的,所以安装gcc的编译环境

    yum install gcc-c++

  6. 编译

    make

    当最后看到:Hint: It’s a good idea to run ‘make test’

    【15W字长文】主从复制高可用Redis集群,完整包含Redis所有知识点相关推荐

    1. Redis高可用之集群配置(六)

      0.Redis目录结构 1)Redis介绍及部署在CentOS7上(一) 2)Redis指令与数据结构(二) 3)Redis客户端连接以及持久化数据(三) 4)Redis高可用之主从复制实践(四) 5 ...

    2. Redis进阶-高可用:集群

       前言 前面几篇文章中,已经介绍了Redis的几种高可用技术:持久化.主从复制和哨兵,但这些方案仍有不足,其中最主要的问题是存储能力受单机限制,以及无法实现写操作的负载均衡. Redis集群解决了上述 ...

    3. Redis(3)-高可用与集群

      Redis 高可用与集群 虽然 Redis 可以实现单机的数据持久化,但无论是 RDB 也好或者 AOF 也好,都解决 不了单点宕机问题,即一旦单台 redis 服务器本身出现系统故障.硬件故障等问题 ...

    4. 高可用 Canal集群( 秒懂 + 史上最全)

      文章很长,而且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 : 免费赠送 :<尼恩Java面试宝典> 持续更新+ 史上最全 + 面试必备 2000页+ ...

    5. gitee如何搭建mysql_MySQL高可用架构集群环境搭建手册.md

      # MySQL高可用架构集群环境搭建手册 ## 环境准备 ### 机器规划 | 节点 | IP | 配置 | 角色 | | -------- | -------------- | ---- | --- ...

    6. 自建k8s平台-高可用k8s集群

      自建k8s平台-高可用k8s集群 一.前置概念与操作 1.内核升级 3.10内核在大规模集群具有不稳定性 内核升级到4.19+ # 查看内核版本 uname -sr # 0.升级软件包,不升级内核 y ...

    7. 搭建高可用mongodb集群(二)—— 副本集

      2019独角兽企业重金招聘Python工程师标准>>> 在上一篇文章<搭建高可用MongoDB集群(一)--配置MongoDB> 提到了几个问题还没有解决. 主节点挂了能 ...

    8. 构建高可用ZooKeeper集群(转载)

      ZooKeeper 是 Apache 的一个顶级项目,为分布式应用提供高效.高可用的分布式协调服务,提供了诸如数据发布/订阅.负载均衡.命名服务.分布式协调/通知和分布式锁等分布式基础服务.由于 Zo ...

    9. corosync+pacemaker实现高可用(HA)集群(二)

      部署方案二(推荐):corosync+pacemaker 利用ansible自动安装corosync和pacemaker 注:关于ansible的具体使用可参见"ansible实现自动化自动 ...

    10. 如何构建高可用ZooKeeper集群

      ZooKeeper 是 Apache 的一个顶级项目,为分布式应用提供高效.高可用的分布式协调服务,提供了诸如数据发布/订阅.负载均衡.命名服务.分布式协调/通知和分布式锁等分布式基础服务.由于 Zo ...

    最新文章

    1. 与跨国巨头合作,做羊还是做狼? --- 我看SAP取消HAND合作伙伴资格
    2. 在WPF应用程序中利用IEditableObject接口实现可撤销编辑的对象
    3. JavaScipt中的Math.ceil() 、Math.floor() 、Math.round()
    4. render在python中的含义_python-/ render()上的Django TypeError获得了意外的...
    5. Java之品优购课程讲义_day17(2)
    6. Python--第2次平时作业
    7. apache camel 相关配置_使用apache camel从表中选择数据-问答-阿里云开发者社区-阿里云...
    8. 2020年十大开源漏洞回顾
    9. tensorflow2.1学习--tf.keras学习之tf.keras.models.Sequential
    10. 最小化安装CentOS 7后,图形界面的安装(GNOME、KDE等)
    11. 电力电子仿真软件Plecs数据类型
    12. 自己的部分小软件合计 2000 - 2013
    13. BT601/BT709/BT2020 YUV2RGB RGB2YUV 公式
    14. profibus GSD文件详解
    15. java线程状态切换图
    16. 几种常用的操作系统调度策略
    17. hardfault常见原因_stm32 HardFault_Handler调试及问题查找方法
    18. Android自定义锁屏实现----仿正点闹钟滑屏解锁
    19. 如何在表格里做计算机统计表,excel怎么制作统计表格 excel统计表怎么添加标题...
    20. Python 使用 LibSVM

    热门文章

    1. html5 三国杀,OL还更新HTML5吗?不更新不充值了
    2. ctfshow每周挑战-极限命令执行
    3. python中国最好大学排名_三分钟实现爬取中国前20大学排名
    4. can和could的用法_情态动词:can与could的用法详解
    5. 36 | 职业发展:应聘安全工程师,我需要注意什么?
    6. 【搜集+亲测】无法注册Flash Player的Activex控件最终解决方法(亲测,WIN7 64位系统)
    7. Golang seelog 使用入门简介
    8. lightroom 闪退_【HTTP网球iOS】Lightroom解锁
    9. java多线程listview_ListView的优化
    10. 计算机专业小论文题目,计算机专业小类论文题目 计算机专业小论文题目怎样拟...