相同点:分布式和集群都是须要有不少节点服务器经过网络协同工做完成总体的任务目标。html
区别:java
【注】分布式中的每个节点,均可以作集群。 而集群并不必定就是分布式的。linux
举个例子说明:
一个小饭店里,原来只有一个厨师,买菜洗菜切菜炒菜全都是这厨师一人干,这叫 单机结构 。后来饭店客人多了,一个厨师确实忙活不过来,因而饭店又请来了个厨师,如今饭店有了两个厨师,这两个厨师都能从头至尾作同样的菜,这两个厨师就是 集群 。这样两个厨师集群确实能作更多的活,客人点10个菜能够分配每一个人抄5个,单个厨师压力减小了。可是这样还不行,为了让厨师专心作菜,把菜作得更好,因而饭店又请来了采购和配菜师,采购负责买菜,配菜师负责把菜挑拣洗好切好给厨师作好准备,那么采购、配菜师、厨师之间就行程了 分布式系统 。后来一个采购和一个配菜师也忙不过来了,因而又再请多了个采购和配菜师,那么两个采购又造成了集群,两个配菜师也造成了集群,一样两个厨师也仍是集群,这样多个集群一块儿就行程了 分布式集群系统 。web
分布式和集群的关系:面试
分布式主要的功能是将咱们的系统模块化,将系统进行解耦,方便咱们的维护和开发。可是其并不能解决并发问题,也没法保证咱们的系统在服务器宕机后的正常运转。redis
集群刚好弥补了分布式的缺陷,集群,就是多个服务器处理相同的业务,一方面能够解决或者说改善咱们系统的并发问题,另外一方面能够解决咱们服务器若是出现必定数量的宕机后,系统仍然能够正常运转。算法
为何用分布式?spring
传统的项目中咱们将各个模块放在一个系统中,系统过于庞大,开发维护困难,各个功能模块之间的耦合度高,没法针对单个模块进行优化。而使用分布式架构将系统模块化,便于咱们的维护和开发。sql
咱们的项目之因此利用分布式架构开发,是由于整个项目实现的功能较多,使每一个功能模块独立出来,下降了各系统之间的耦合度,增删一个功能不会影响其余功能模块。数据库
为何用集群?
项目若是部署在一台Tomcat上,全部的请求都由这一台服务器处理,会存在很大风险:
集群是是指将多台服务器集中在一块儿,每台服务器都实现相同的业务,作相同的事情。可是每台服务器并非缺一不可,存在的做用主要是缓解并发压力和单点故障转移问题。
两大特色:可扩展性、高可用性
两大能力:负载均衡、错误恢复
SOA:面向服务的架构。也就是把工程都拆分红服务层工程、表现层工程。服务层中包含业务逻辑,只须要对外提供服务便可。表现层只须要处理和页面的交互,业务逻辑都是调用服务层的服务来实现。工程均可以独立部署。
项目基于SOA的架构,表现层和服务层是不一样的工程。因此要实现商品列表查询须要两个系统之间进行通讯。如何实现远程通讯?
使用dubbo。使用rpc协议进行远程调用,直接使用socket通讯,传输效率高,而且能够统计出系统之间的调用关系、调用次数,管理服务。
Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案。
(注意不要与负载均衡搞混:负载均衡是对外提供一个公共地址,请求过来时经过轮询、随机等,路由到不一样的服务器。)
Dubbo有5种节点角色:
流程:
0. 服务容器用来启动、加载、运行服务提供者;
1. 服务提供者在启动时,向注册中心注册本身提供的服务;
2. 服务消费者在启动时,想注册中心订阅本身所需的服务;
3. 注册中心返回服务提供者地址列表给消费者。若是有变动,注册中心将基于长链接推送变动数据给消费者;
4. 服务消费者从提供者地址列表中,(基于软负载均衡)选一台服务提供者进行调用,若是调用失败,再选另外一台调用;
5. 服务提供者和消费者,在内存中累计调用次数与调用时间,定时每分钟发送统计数据到监控中心。
注册中心存储着Provider注册的远程服务,并将其所管理的服务列表通知给服务消费方(Consumer),且注册中心和提供方和消费方之间均保持长链接,能够获取Provider发布的服务的变化状况,并将最新的服务列表推送给Consumer。
Dubbo的注册中心有Zookeeper、Redis、Multicast、Simple等。咱们使用的是Zookeeper。
服务定义部分放在服务提供方的xml文件:在提供方增长暴露服务配置<dubbo:service>
<!-- ================项目中服务层为提供方,使用dubbo发布服务=================== --> <!-- 提供方应用信息,用于计算依赖关系 --> <dubbo:application name="taotao-manager" /> <dubbo:registry protocol="zookeeper" address="192.168.25.129:2181" /> <!-- 用dubbo协议在20880端口暴露服务 --> <dubbo:protocol name="dubbo" port="20880" /> <!-- 声明须要暴露的服务接口 --> <dubbo:serviceinterface="com.taotao.service.ItemService" ref="itemServiceImpl" />
服务引用部分放在服务消费方的xml文件:在消费方增长引用服务配置<dubbo:reference>
<!-- ================项目中表现层为消费方,引用dubbo服务======================= --> <dubbo:application name="taotao-manager-web" /> <dubbo:registry protocol="zookeeper" address="192.168.25.129:2181" /> <dubbo:referenceinterface="com.taotao.service.ItemService" id="itemService" />
【注】address的值是本身的zookeeper所在系统的ip地址和端口,若是是集群,就用逗号分开:
<dubbo:registry protocol="zookeeper" address="192.168.25.140:2181,192.168.25.140:2182,192.168.25.140:2183" /dubbo:registry>
默认也推荐使用netty框架,还有mina。
ZooKeeper是一个开源的分布式协调服务,它是集群的管理者,监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操做。最终,将简单易用的接口和性能高效、功能稳定的系统提供给用户。
分布式应用程序能够基于Zookeeper实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能。
服务器角色:Leader、Follower、Observer
Zookeeper 下Server工做状态:
服务器具备四种状态,分别是Looking、Following、Leading、Observing。
Leader 选举:半数经过
每次投票后,服务器都会统计投票信息,判断是否已经有过半机器接受到相同的投票信息,若是有,此时便认为已经选出了Leader。
个人这篇博客Redis面试题
还有一篇读书笔记《Redis开发与运维》
像项目中首页的大广告和商品类目这些不须要常常修改的数据,若是用户每次刷新页面的时候都要去数据库中查询,这样会浪费资源和增长数据库的压力。因此咱们想当把这些数据添加到一个缓存中,用户去访问的时候,先去缓存中查询,若是没有,再去数据库中查询,而后把查询到的数据添加到缓存中。(操做缓存就是直接操做内存,因此速度至关快)
Redis是一种基于 key-value 对的非关系型数据库(nosql),与不少键值对数据库不一样的是,Redis中的值能够是由string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)等多种数据结构和算法组成,所以Redis能够知足不少的应用场景。并且由于Redis会将全部数据都存放在内存中,因此它的读写性能很是惊人。不只如此,Redis还提供了持久化功能(RDB和AOF),防止redis宕机时的数据丢失。(能够将内存的数据利用快照(RDB)和日志(AOF)的形式保存到硬盘上,这样在发生相似断电或者机器故障的时候,内存中的数据不会“丢失”)。
Redis的主要缺点是数据库容量受到物理内存的限制,不能用做海量数据的高性能读写,所以Redis适合的场景主要局限在较小数据量的高性能操做和运算上。
咱们使用的是spring与jedis整合的客户端,能够利用jedis作分片式集群,解决了redis内存受限的问题。
使用集群的缘由就是 单台服务器并发处理能力有限,而且一旦服务器故障,整个服务就没法访问了。集群就是将多台服务器都集中在一块儿,每台服务器都实现相同的业务,而且若有一台服务器发生故障,他所运行的业务能够被其余服务器进行接管,这样就缓解并发压力和单点故障转移问题,保障了redis的性能。
搭建redis集群的步骤:
(至少3个节点,为了集群的高可用,为每个节点增长一个备份机。(6台服务器,3主3从)。搭建伪分布式集群方案:在一台机器里面运行6个redis实例。端口须要不一样(7001-7006)。)
一、首先在linux系统上安装一个redis:步骤就是【首先上传redis源码包(put)并解压(tar -zxvf),而后进行编译(make)和安装】
二、而后建立咱们集群要安装的目录(redis-cluster),copy以前搭建好的redis共6份,而后分别进入其bin目录修改redis.conf配置文件,分别更改端口号(为7001到7006),并开启集群cluster-enabled yes。
三、Redis 官方提供了 redis-trib.rb 这个工具来建立集群,这个工具是用ruby脚本实现的,因此须要安装ruby:
yum -y
install
ruby ruby-devel rubygems rpm-build
gem
install
redis
四、而后使用ruby脚本搭建集群。从解压目录下的src下的拷贝redis-trib.rb文件到redis-cluster目录中 cp redis-trib.rb /usr/local/redis-cluster/,接着执行下面命令就可完成安装:
[root@localhost redis-cluster]# ./redis-trib.rb create --replicas 1 192.168.25.153:7001 192.168.25.153:7002 192.168.25.153:7003 192.168.25.153:7004 192.168.25.153:7005 192.168.25.153:7006
redis cluster在设计的时候,就考虑到了去中心化,去中间件,也就是说,集群中的每一个节点都是平等的关系,每一个节点都保存各自的数据和整个集群的状态。每一个节点都和其余全部节点链接,并且这些链接保持活跃,这样就保证了咱们只须要链接集群中的任意一个节点,就能够获取到其余节点的数据。
Redis 集群没有并使用传统的一致性哈希来分配数据,而是采用一种叫作哈希槽 (hash slot)
的方式来分配数据的。redis cluster 默认分配了 16384 个slot,当须要在 Redis 集群中放置一个 key-value 时,redis先对key使用crc16算法算出一个结果,而后把结果对16384求余数,这样每一个key都会对应一个编号在 0-16383之间的哈希槽,redis会根据节点数量大体均等的将哈希槽映射到不一样的节点。
Redis 集群会把数据存在一个 master节点,而后在这个 master 和其对应的salve之间进行数据同步。当读取数据时,也根据一致性哈希算法到对应的 master 节点获取数据。只有当一个master 挂掉以后,才会启动一个对应的 salve 节点,充当 master 。
须要注意的是:必需要3个或以上
的主节点,不然在建立集群时会失败,而且当存活的主节点数小于总节点数的一半时,整个集群就没法提供服务了。
http://www.javashuo.com/article/p-mxdparyf-gg.html
采用以下策略:
为何?
读的逻辑你们都很容易理解,谈谈更新。若是不采起我提到的这种更新方法,你还能想到什么更新方法呢?大概会是:先删除缓存,而后再更新数据库。这么作引起的问题是,若是A,B两个线程同时要更新数据,而且A,B已经都作完了删除缓存这一步,接下来,A先更新了数据库,C线程读取数据,因为缓存没有,则查数据库,并把A更新的数据,写入了缓存,最后B更新数据库。那么缓存和数据库的值就不一致了。
另外有人会问,若是采用你提到的方法,为何最后是把缓存的数据删掉,而不是把更新的数据写到缓存里?这么作引起的问题是,若是A,B两个线程同时作数据更新,A先更新了数据库,B后更新数据库,则此时数据库里存的是B的数据。而更新缓存的时候,是B先更新了缓存,而A后更新了缓存,则缓存里是A的数据。这样缓存和数据库的数据也不一致。
Redis支持RDB和AOF两种持久化机制,持久化功能有效地避免因进程退出形成的数据丢失问题,当下次重启时利用以前持久化的文件便可实现数据恢复。
RDB持久化:是把当前进程数据生成快照保存到硬盘的过程。触发RDB持久化过程分为手动触发(save、bgsave)和自动触发。
AOF(append only file)持久化:以独立日志的方式记录每次写命令,重启时再从新执行AOF文件中的命令达到恢复数据的目的。AOF的主要做用是解决了数据持久化的实时性。
AOF默认是默认不开启的,开启AOF功能须要设置配置:appendonly yes。
AOF缓冲区同步文件策略,由参数appendfsync控制:
appendfsync always #每次有数据修改发生时都会写入AOF文件,这样会严重下降Redis的速度
appendfsync everysec #每秒钟同步一次,显示地将多个写命令同步到硬盘
appendfsync no #让操做系统决定什么时候进行同步
【注】若是同时配了RDB和AOF,优先加载AOF。
redis中存放数据都是key -value的形式。
咱们商城使用String格式来存放的。拿商品来讲:商品的Id就是Key ,商品相关的商品信息组成一个JSON存放。
用到了数据库事务
<!-- 事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 数据源 --> <property name="dataSource" ref="dataSource" /> </bean> <!-- 通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- 传播行为 --> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="create*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="find*" propagation="SUPPORTS" read-only="true" /> <tx:method name="select*" propagation="SUPPORTS" read-only="true" /> <tx:method name="get*" propagation="SUPPORTS" read-only="true" /> </tx:attributes> </tx:advice> <!-- 切面 --> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.taotao.service.*.*(..))" /> </aop:config>