小型项目(体量比较小,用户比较少这种)LAMP === linux操作系统 + apache httpd + mysql + php
把应用服务器+数据库等部署到同一台服务器上
随着用户量/数据量的增加,服务器压力就比较大,很容易出现死机等问题。
一种解决方式就是升级硬件(性价比是很低,cpu或者内存升级效能不是成倍,价格翻5倍,性能可能只能提升一倍)
第二种方式 1 + 1 > 1 (由一台服务器变成2台服务器,成本增加一倍,处理的效果也可能会增加一倍)
把应用服务器和数据库服务器分离
随着用户量增多,虽然服务器目前可以扛得住,但访问速度比较慢,影响用户体验
本地缓存 mybatis 一级缓存二级缓存
远程缓存 redis memcache
使用缓存会大大的提升访问速度
### (4)数据库设计的改变- 分库分表、读写分离、集群
分库 – 解决数据库的压力和优化数据设计,数据都集中在一个库中一是有些项目的表非常非常多,不便于管理,二是数据库的压力
分表 – 有些表可能会非常大或者数据量多或者数据字段很多,会导致查询的效率比较低,有的表有上亿条记录
横向拆分: 减少单表的数据量,提升查询效率
纵向拆分:把一个表中的字段拆到几个表中,有些字段是常用,有些字段是很少使用的
集群(主从复制),读写分离
一般可以采用主从复制的集群方式(一主多从的方式),主机负责写操作,从机负责读操作。
开发中可以使用sharingJDBC这种方式可以操作集群
随着用户的增加,由于提供了分库分表/读写分离/缓存,数据这一块暂时不会存在什么瓶颈,但是应用服务器的访问压力还是很大,把服务器做成集群的形式,tomcat的并发访问量几百
其他的瓶颈基本解决,用户由于所在的地区不同,导致网路速度也不一定一样,有些用户的访问速度就会有比较大的影响,如何去优化
CDN加速 — 租借运营商的服务器,把资源放在这个服务器上,用户访问速度非常快
反向代理 – 做负载均衡,提升访问速度
可以把一些图片等静态资源放在云服务器上,减轻服务器的负担,提升访问速度
有些数据不一定都存放在关系型数据中,可以放在NoSQL型数据库比如Mongodb,Redis等
系统中的数据量很大 ,用户在查询的时候效率比较低,可以考虑使用全文检索技术提升查询的速度
比如使用ElasticSearch(es)
可以使用MQ完成异步任务,分布式事务,发布和订阅等
虽然采用分布式和集群的方式提升用户的访问速度,减轻服务器的压力,但整体还是中心化处理方式SOA
把一个项目分割成很多个小的项目,可以独立开发、独立部署,可以让程序员更专注业务上的开发
由于涉及到分布式应用,所以开发难度大大的增加。
SpringCloud体系
服务的注册与发现 Eureka
分布式远程调用Feign客户端
负载均衡 Ribbon
断路器 hystrix 服务的降级/熔断/限流
网关服务zuul
远程配置config
Dubbo体系(阿里开源项目)+ zookeeper(服务的注册与发现)
分布式和集群的区别?
把一个项目拆分后放到不同的服务器上,调用的时候需要跨服务器调用,分布式
集群把同样的内容复制多份放到不同的服务器上
负载均衡的概念?
提供一种算法或者策略来访问集群中的哪台服务器。
轮询算法 按顺序轮流访问
权重算法 根据设置的权重来确定访问的频率
hash算法 根据hash值来确定访问哪台服务器
约定大于配置(基于Maven)
减少灵活性,有一些规定,按照规定来操作减少一些配置
配置文件 springboot的配置文件application.yml或者application.properties只需要放在src/main/resources/即可,不要特别在哪里去配置声明
开箱即用
不像ssm中需要配置很多东西,比如web.xml,applicationContext.xml spring-mvc.xml mybatis-config.xml等,springboot不要任何配置,可以直接正常运行
springboot为什么不需要配置能开箱即用?
主要就是因为springboot提供自动装配机制
@SpringBootApplication
public class SpringbootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootDemoApplication.class, args);
}
}
@SpringBootApplication
----1 @SpringBootConfiguration
------@Configuration 定义当前类是一个配置类,springioc启动的时候会自动加载配置类
----2 @EnableAutoConfiguration
-----2.1@AutoConfigurationPackage 获取主类所在的包名,会扫描该包及子包的所有的类
-----2.2@Import(AutoConfigurationImportSelector.class) 自动配置类的导入(一些自动配置生效)
会找META-INF/spring.factories # Auto Configure的内容读取进来
把所有满足条件的自动配置类加载到ioc容器中(配置生效)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
public class WebMvcAutoConfiguration { //满足以上3个条件,自动配置类会被加载生效
----3 @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) 指定扫描的包
Redis(Remote Dictionary Server)是完全开源免费的,遵守BSD协议,是一个高性能的key-value内存型数据库
① Redis支持数据持久化,可以将内存中的数据保存在磁盘中,重启以后可以再次加载进行使用。
② Redis支持的数据类型十分丰富,不仅支持key-value类型,同时还提供了list,set,zset,hash等数据结构的存储。
③ Redis支持数据的备份,master-slave模式的数据备份。
Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache, and message broker. Redis provides data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes, and streams. Redis has built-in replication, Lua scripting, LRU eviction, transactions, and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster
Redis默认有16个数据库
Redis的默认端口号6379
操作redis的java第三包jedis
一、性能高 —— Redis能读的速度是110000次/s,写的速度是81000次/s。
二、丰富的数据类型—— Redis支持二进制案例的Strings,Lists,Sets及Ordered Sets数据类型操作。
五大基本数据类型:strings, hashes, lists, sets, sorted sets
①字符串string map.put(“name”,“张三”)
②哈希hash
③列表list 双向队列
④集合set 无序不能重复
⑤有序集合zset 有序 score 不能重复
扩展的数据类型: bitmaps, hyperloglogs, geospatial indexes, and streams
三、原子性——Redis的所有操作都是原子性的,操作要么成功要么失败要么不执行。单个操作是原子性的。多个操作也是支持事务,即原子性,通过MULT和EXEC指令包起来。
四、功能丰富性——Redis还支持publish/subscribe,通知,key过期。
五、单线程,多线程的效率不一定比单线程的效率高,主要就是存在线程的切换
一般有阻塞操作的时候多线程的效率优势才能体现出来
Redis为什么使用单线程?
(1)由于redis是内存型数据库,访问速度已经非常快,而且没有IO操作(比较耗时),假如使用多线程,由于多线程存在线程的切换(栈帧的切换,上下文读取,程序计数器等),可能效率比单线程要低很多
(2)redis采用epoll模型,使用nio的模型,所以通讯效率也比较高
单点登陆/直播平台里面在线好友列表/抢购 秒杀/商品的排行榜/点赞/数据过期
set age 33
multi //打开事务
set age 10
set age 20
exec //让命令按顺序执行
get age
discard //取消事务 其实就是清空事务的命令队列并退出事务上下文,也就是我们常说的事务回滚。
(1)事务没有原子性,语法没有错误
multi
set a 123 //string类型
lpop a //redis语法没有错误,但a是字符串类型,不能使用lpop指令
exec//提交事务,会出现第一条指令仍然执行成功
(2)事务有原子性,语法错误上
multi
set a 123
sadf
exec //事务由于语法有错误,自动丢弃回滚事务
由于Redis的数据都存放在内存中,如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能,将数据保存到磁盘上,当redis重启后,可以从磁盘中恢复数据。redis提供两种方式进行持久化,一种是RDB持久化(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化),另外一种是AOF持久化(原理是将Reids的操作日志以追加的方式写入文件)。那么这两种持久化方式有什么区别呢,改如何选择呢?
RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
注意:由于redis是单线程,主进程主要是来读写内存,假如进行持久化(IO操作)使用主进程的话,主进程就不能读写内存,要停下等待IO操作(相比比较耗时),所以Redis设计会fork一个子进程进行持久化操作,主进程还可以进行读写操作。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0CWh2odL-1665818550874)(E:\ziliao\youdao\[email protected]\2c34e4772e2c4d5aa4294d2e090db9ac\njyjyvf.png)]
RDB持久化配置
Redis会将数据集的快照dump到dump.rdb文件中。此外,我们也可以通过配置文件来修改Redis服务器dump快照的频率,在打开6379.conf文件之后,我们搜索save,可以看到下面的配置信息:
save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。
save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照。
save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照。
AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
AOF持久化配置
在Redis的配置文件中存在三种同步方式,它们分别是:
appendfsync always #每次有数据修改发生时都会写入AOF文件。
appendfsync everysec #每秒钟同步一次,该策略为AOF的缺省策略。
appendfsync no #从不同步。高效但是数据不会被持久化。
RDB存在哪些优势呢?
1). 一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的。比如,你可能打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
2). 对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。
3). 性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。
4). 相比于AOF机制,如果数据集很大,RDB的启动效率会更高。
RDB又存在哪些劣势呢?
1). 如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。
2). 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。
AOF的优势有哪些呢?
1). 该机制可以带来更高的数据安全性,即数据持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。至于无同步,无需多言,我想大家都能正确的理解它。
2). 由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。
3). 如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。
4). AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。
AOF的劣势有哪些呢?
1). 对于相同数量的数据集而言,AOF文件通常要大于RDB文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
2). 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效。
二者选择的标准,就是看系统是愿意牺牲一些性能,换取更高的缓存一致性(aof),还是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行save的时候,再做备份(rdb)。rdb这个就更有些 eventually consistent的意思了。不过生产环境其实更多都是二者结合使用的。
RDB和AOF同时开启
三种方式:
(1)主从复制方式
在一主多从的情况下,主服务器垮掉,不能进行写操作,从服务器可以正常进行读操作
一个从服务器垮掉,暂时不会影响读写操作
一般不建议大家使用
(2)哨兵模式sentinel
一般会选择奇数个哨兵监控主服务器,会定时发送心跳到主服务器,主服务器回应说明主服务器健康,假如在一定次数仍然没有回应,哨兵会判定该主服务器宕机等,会投票选举从服务器,票数多的从服务器升级为主服务器,可以进行写操作,其他的从服务器作为该服务器的从服务器
(3)集群cluster
把Redis的集群分成slot槽,分成16384个插槽
会把放入到redis的数据经过hash运算等到对应的槽,把数据放入到对应的服务器上,取得时候也是通过hash值获取。
缓存命中率: 在缓存中可以查询到数据不用到数据库中查询这个就是缓存的命中,缓存的命中率越高,数据库的压力越小,效率也是越高
缓存的雪崩
当有大量不同请求同时到达缓存服务器,这时由于缓存过期或者或缓存服务器出现问题等,所有的请求都会提交到数据库来进行处理,这时候有可能会造成数据库服务器的崩溃,缓存的雪崩
解决方法
(1)设置redis集群和DB集群的高可用,如果redis出现宕机情况,可以立即由别的机器顶替上来。这样可以防止一部分的风险。
3h - 高性能 高可用 高并发
高性能: redis缓存
高可用: 集群
高并发: juc多线程并发,同步/锁
(2)使用互斥锁
在缓存失效后,通过加锁或者队列来控制读和写数据库的线程数量。比如程查:对某个key只允许一个线询数据和写缓存,其他线程等待。单机的话,可以使用synchronized或者lock来解决,如果是分布式环境,可以是用redis的setnx命令或setex来解决。
(3)不同的key,可以设置不同的过期时间,让缓存失效的时间点不一致,尽量达到平均分布。
(4)永远不过期
redis中设置永久不过期,这样就保证了,不会出现热点问题,也就是物理上不过期。
(5)资源保护
使用netflix的hystrix,可以做各种资源的线程池隔离,从而保护主线程池。
缓存的穿透
当有大量的请求到缓存服务器,缓存服务器中不存在该数据,数据库也不存在这个数据,这样也可能造成所有的请求到达数据库服务器,造成数据库服务器的瘫痪
常出现网络恶意攻击 http://www.taobao.com/proc/1888 (不存在这个商品)
解决方法
1.设置布隆过滤器
布隆过滤器是一个bitmap集合(数组),这个数组只存放0和1,在访问数据的时候由布隆过滤器先行过滤判断是否存在该数据 ,存在该数据才提交数据库查询访问,不存在该数据,不需要提交给数据库,大大减轻了数据库的负担,避免了缓存的穿透带来的问题
布隆过滤器存在的问题
(1)hash碰撞的问题
解决方式,增加bit数组的长度或者增加hash函数的个数
(2)存在删除的问题
由于存在hash碰撞的问题,删除的时候可能会影响其他的值
假如操作少的话无需处理,删除多的话,可以定时重构过滤器数据(过滤器和数据库数据匹配)
实现方式: google里提供了BloomFilter
Redission中RBloomFilter
2.如果一个查询返回的数据为空,不管是数据不存在还是系统故障,我们仍然把这个结果进行缓存,但是它的过期时间会很短
查不到的数据也进行缓存,避免了再次查询该无结果的数据会穿透缓存到数据库查询,给数据库造成压力
最长不超过5分钟。
3.在设计上处理穿透问题
显示点赞数
点赞数要是放入缓存,点赞增删改是不是比较频繁
可以在有增删改的时候暂时不清除缓存,会造成数据的不一致,如数据库中的点赞数300,缓存中的点赞数只有280,点赞数对数据一致性的要求高不高??
缓存的击穿
当有大量的请求同一个数据到缓存服务器,这时候缓存服务器不存在(有可能是缓存过期或者第一次访问),请求打到数据库上,数据库存在这个内容,需要数据库处理,导致数据库瘫痪等,这种一般都是访问热点商品,
解决方式:可以将热点数据设置为永远不过期;
或者基于 redis or zookeeper 实现互斥锁,使用Redission 等待第一个请求构建完缓存之后,再释放锁,进而其它请求才能通过该 key 访问数据。
正向代理和方向代理的区别
正向代理
当我们需要访问一下外国网站时由于一定的原因,无法正常访问,此时找到一个可以访问国外网站的代理服务器,我们将请求发送给代理服务器,代理服务器去访问国外的网站,然后将访问到的数据传递给我们!
上述这样的代理模式称为正向代理,正向代理最大的特点是客户端非常明确要访问的服务器地址;服务器只清楚请求来自哪个代理服务器,而不清楚来自哪个具体的客户端;正向代理模式屏蔽或者隐藏了真实客户端信息。
客户端必须要进行一些特别的设置才能使用正向代理。
反向代理
反向代理的处理方式,例如某宝网站,每天同时连接到网站的访问人数已经爆表,单单个服务器不能满足用户访问量的要求,就出现分布式部署;也就就是用户访问URL时,nginx通过一定的规则把用户的请求分发到不同的服务器上,实现负载均衡。
实际运行方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。
示意图:
作用:反向代理,承担负载均衡器的作用
分布式应用系统的理论CAP:
C-一致性 A-可用性 P-分区容错性 不能同时保证这3点
大部分的应用都遵循要么CP,要么AP,很少CA(只能是单机才可能同时满足CA,不能存在P)