一、feign使用
openFeign:调用远程就像调用本地一样
协议:http协议
底层技术:httpclient
服务注册发现:
https://nacos.io/zh-cn/
案例一:
电影票购买系统,包括组件:销售、订单、电影院—每个系统对应自己独立数据库
1、销售系统从电影院拉取正在上映的电影票——>销售
电影系统只需在数据库中手动放入电影票,销售获取到电影票后需要先保存到本地数据库,再展示到页面
2、用户下单后把订单保存到订单系统
3、用户在销售系统可以查看自己的订单
用户能看到的系统是:销售系统
1、springcloud的版本需要和springboot的版本匹配(www.spring.io)
2、springcloud —->open fegin —->调用远程就像调用本地代码一样
fegin: 是http协议
post请求的数据 需要加@RequestBody 注解,从body取数据
3、任何代码如果重复拷贝三次那么就需要考虑重构(封装)
4、定时调度:-spring自带定时调度器
@EnableScheduling 开启定调度
二、微服务治理一、注册发现
1、服务发现治理——->把微服务向注册服务器注册——->微服务之间的访问通过注册服务器发现
我们用的技术是阿里的nacos
nacos 使用
1、创建nacos数据库,并创建表初始化数据
2、在application.properties 进行配置
server.port=8848 #配置端口号 8848 是世界最高峰的高度
db.url.0=jdbc:mysql://192.168.244.11:3306/J185_nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=1234
3、把nacos-mysql.sql 配置文件导入到新建的数据库
4、进入bin文件夹,执行【单机启动.bat】
5、访问nacos地址http://192.168.60.1:8848/nacos/index.html,
默认账号为nacos 密码为nacos
6、在项目中引入服务发现的坐标
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
2.2.4.RELEASE
6、在配置文件中配置nacos地址,给应用程序取一个名字
spring:
application:
name: movieSys
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
三、MQ消息队列
1、队列 ——>线性结构 先进先出 (相对数组来说就是只有添加、删除)
应用的场景:生产者和消费者模式 ——>消峰的作用
队列是一个异步的处理——->把一件事情分成两步来实现
主流的mq: kafka、rabbitmq、rocketmq、activemq
docker run -d -p 5672:5672 -p 15672:15672 —name rabbitmq rabbitmq:management
#5672 tcp/IP端口—代码中使用 15672 是http的端口—-控制台
MQ 进行对象传输的时候需要进行序列化和反序列—->因为它是TCP/IP协议
//spring封装rabiitmq的代码 RabbitTemplate
//注入工厂(已经预加载)
@Autowired
CachingConnectionFactory connectionFactory;
//rabbitmq模板
@Bean(value = “rabbitTemplate”)
public RabbitTemplate rabbitTemplate(){
return new RabbitTemplate(connectionFactory);
}
作业: 1、用户下单后需要把订单保存到订单系统,状态改0(支付成功未出票),返回给用户
2、把订单通过MQ发送到电影系统,电影系统根据电影名修改票数(出票),并把订单保存到电影院系统
3、电影院系统通过fegin调用订单系统接口,把订单修改为1(出票成功)或2(出票失败)
RabiitMQ交换机:
1、默认交换机:DirectExchange —->交换机名+路由KEY
2、主题交换机: TopicExchange——->交换机名+路由KEY(模糊匹配)
*(星号)可以代替一个单词
#(井号)可以代替零个或多个单词
3、扇型交换机 FanoutExchange ——->广播模式(订阅发布模式),不需要key,把消息投递到绑定的队列中去
4、头交换机 —->把规则放到发送内容中
注意:队列尽量不要绑定到不同的交换机,一个交换机是允许绑定多个队列
在rabbitmq中如何保证数据不丢失?
spring:
rabbitmq:
host: 172.16.1.253
port: 5672
username: admin
password: 123456
publisher-confirm-type: correlated
virtual-host: /
listener:
simple:
acknowledge-mode: manual #开启ACK
retry:
max-attempts: 5 #重试次数
initial-interval: 5000 #重试间隔时间
enabled: true #开启消费重试
default-requeue-rejected: false #重试次数超过
生产者:
RabbitTemplate.ConfirmCallback callback=(CorrelationData correlationData, boolean b, String s)->{
}
//开启手动确认
rabbitTemplate.setMandatory(true);//开启消息确认
//绑定回调函数
rabbitTemplate.setConfirmCallback(callback);
//创建关联数据对象
CorrelationData correlationData=new CorrelationData(orderNum);
死信
练习: 下单后弹出一个窗口,显示正在支付(需要有正在加载的效果,页面等待5秒钟),当消息投递到队列后,加载效果消失,显示支付成功等待出票或 支付失败 或出票成功
四、治理二、负载均衡 - —->冗余
负载均衡——->1、分摊IO流 2、灾备
常用的负载均衡算法:1、轮询 2、ip_hash 3、hash一致算法
Netflix -ribbon 组件来实现的负载均衡
第五、治理三、熔断
熔断———>服务降级处理——->避免服务雪崩
Netfilx -hystrix 组件
@EnableCircuitBreaker //开启熔断
@HystrixCommand(fallbackMethod = “twoInfoHystrix”)
public String twoInfo(int tag){
return service.twoInfo(tag);
}
public String twoInfoHystrix(int tag){return "系统暂时无法访问";}
@FeignClient(name = “sysTwo”,fallback = TwoHystrixService.class)
//要开启feign熔断机制
feign:
hystrix:
enabled: true
第六服务治理四-集中配置
1、 把所有微服务的配置放到一个服务器上,进行集中配置
2、我们用nacos来做集中配置服务
springboot 默认配置: bootstrap application 前者会优先启动
后缀: properties yml 前者优先与后者
spring:
application:
name: sysOne
cloud:
nacos:
config:
server-addr: 172.16.1.253:8848
file-extension: yml
prefix: sysOne
profiles:
active: dev
第七服务治理五-网关
网关用springcloud —->gateway (所用的框架是springweb flow 来实现的MVC)
网关做的事情:1、过滤 2、路由
作业:
1、销售、订单、电影院 需要注册发现和集中配置
2、通过网关:1、查询用户的所有订单——>订单系统
2、查询所有电影票——->电影票系统
3、查询正在出售的电影——>销售系统
第八服务治理日志处理
第九-redis
redis 是非关系型数据库(NO-SQL),是内存数据库,但可以持久化。语法 key-val
redis新版 默认是单线程-所以是线程安全
启动redis服务: redis-server 配置文件名
启动redis客户端:redis-cli -p 端口 -h 服务器地址 -a 认证
docker run -d —name redis -p 6379:6379 redis #docker 安装redis
1 、String
set key val -->添加
get key --->查询
del key--->删除 (通用)
setex key seconds val —设置过期时间 在分布式中可以做全局session
2、hash—->存储对象 ——java(Map集合)
1、 HSET key field value 添加
2、 HGET key fied —->查询
3、 HDEL key filed —->删除某个字段
4、del key —->删除所有
5、hmset key filed val filed val 批量添加
3、List——>队列 —->生产者和消费者(消峰)
队列是一个线型的数据结构,做了一个特殊的处理(先进(放入)先出(删除))
程序中的场景:生产者和消费者模型
(L)Rpush key val—->放
(L)RPOP key —->取
B(L)RPOP key timeout ——>阻塞的取
4、无序集合 —->交集、差集—->(共同好友、推荐好友)
sadd key val val —->添加
sinter key1 key2 ——>交集
sdiff key1 key2 ——->差集
5、有序集合 —->排序—->排行榜
zadd key score val score val….. 添加
ZINCRBY key increment member
有序集合中对指定成员的分数加上增量 increment
排序:zrange key start stop (-1,代表全部) 升序
zrevrange key start stop (-1,代表全部) 降序
redis 可以用来做什么?
1、分布式session
2、分布式协调机制(单线程,数据安全)
3、缓存
4、存储对象
5、生产者消费者模型(队列、栈—->可以是阻塞式)
6、交集差集(共同好友、推荐好友)
7、排行榜
java 操作redies
org.springframework.boot
spring-boot-starter-data-redis
io.lettuce
lettuce-core
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.25.Final</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>
@Bean
public RedisTemplate
RedisTemplate
template.setConnectionFactory(factory);
// 使用Jackson2JsonRedisSerialize 替换默认的jdkSerializeable序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
练习:在电影票销售系统,从数据库查询出需要销售的电影票,放到页面销售。
1、首先判断缓存是否存在电影票,如果不存在就从数据库中查询出来,先放入缓存再返回到页面。
如果缓存中存在就直接返回到页面。缓存时间为5秒。(string)
2、在页面加一个添加到购物车按钮,把信息放入到redis,可以对购物车信息进行 修改数量,删除某张电影票
(hash)
十、缓存
设置缓存的KEY需要根据查询条件来设置
@GetMapping(“movieEntityList/{price}/{tag}”)
public Object movieEntityList(@PathVariable(“price”)float price,
@PathVariable(“tag”)int tag){
String key=price+”-“+tag;
}
jmeter summary report 字段意思
Samples :事务数量
Average:平均一个完成一个事务消耗的时间(平均响应时间)
Median:所有响应时间的中间值,也就是 50% 用户的响应时间,大概是这个意思
Min:最小响应时间
Max:最大响应时间
以上单位都是ms
Std.Dev:偏离量,越小表示越稳定
Error %:错误事务率
Throughtput:每秒事务数,即tps
KB/sec:网络吞吐量
Received KB/sec :每秒从服务器端接收到的数据量(每秒发送多少字节 )
Sent KB/sec :每秒向服务器发送数据量(每秒发送多少字节 )
1、缓存雪崩
if(!redis.hasKey(key)){
List list=movieDao.findAllByPriceAndTag(price,tag);
if(null!=list){
//防止缓存雪崩
int timeCache=ToolUtil.MIN_CACHE_TIME;
long time=(System.currentTimeMillis()+key.hashCode())%ToolUtil.CACHE_TIME;
if(time>ToolUtil.MIN_CACHE_TIME){
timeCache=(int)time;//最小值—-最大值之间的数
}
redis.set(key,list, timeCache);
}
}
2、缓存穿透
public static BloomFilter bloomFilter;
static {
//布隆过滤器,,实现项目中可以在用户添加数据或修改数据的时候放入数据
bloomFilter= BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()),1000000,0.001);
bloomFilter.put("120.0-0");
bloomFilter.put("130.0-0");
}
String key=price+"-"+tag;
//过滤器
if(!ToolUtil.bloomFilter.mightContain(key)){
//非法
return null;
}
//解决方式
1、把null对象也放入缓存,设置较短的缓存时间
2、加布隆过滤器,只允许过滤器中有点条件才进入。
3、缓存击穿
锁—->肯定用在大并发/多线程——>有序的去操作公共资源——>会导致效率降低——>一定不要出现死锁
@Bean
public RLock rLock() {
Config config = new Config();
SingleServerConfig singleServerConfig = config.useSingleServer();
singleServerConfig.setAddress(“redis://172.16.1.253:” + 6379);
singleServerConfig.setTimeout(3000);
// singleServerConfig.setDatabase(database);
// singleServerConfig.setPassword(“123456”);
RLock rLock= Redisson.create(config).getLock(“J185”);
return rLock;
}
促销系统:
1、 拿出100张电影票来进想促销。用户点击抢购电影票,点击后按钮变为不可操作并弹出窗口等待是否抢购成功。
2、用户购买订单放入到队列MQ
3、系统获取队列订单,每2张电影票取一张为成功信息。并把成功信息放入到redis(用户ID+订单)
4、用户等待10秒钟,如果10秒钟在redis没有获得信息为抢购失败,否则为成功
5、活动结束后,写一个定时调度器,把redis信息持久化到关系型数据库
索引数据库ES
1、访问ES服务器用http协议
2、索引数据库-提供全文搜索
索引:让查询效率更快
检索内容——>先找索引—->索引对应的内容
1、索引会占用物理空间
2、索引会让修改变慢
数据库的索引:聚集索引和非聚集索引
聚集索引:数据库自动创建—->第一个不为空的字段(ID)
非聚集索引:我们创建的索引
非聚集索引——>找聚集索引—->找真实的数据
1、经常查询的列上建索引
2、索引失效:
1.查询条件中有or,即使有部分条件带索引也会失效
2.like查询是以%开头
3、sql函数不会用索引
4.违背最左匹配原则
age的索引是和建立再(name,age)组合索引的基础上,当查询条件中没有第一个组合索引的字段(name)会导致索引失效
5、大文本不能使用索引 ——>会导致索引空间快速增加
全文搜索:把文章里面的 字或词组建索引——->检索出文章
org.springframework.boot
spring-boot-starter-data-elasticsearch
spring:
elasticsearch:
rest:
uris: http://172.16.1.254:9200
@Data
@Document(indexName = “news_index”)
public class NewsEntity {
@Id
@Field(type=FieldType.Keyword) //不建索引
private String newsId;
@Field(type = FieldType.Text)
private String newsInfo;
@Field(type=FieldType.Keyword) //不建索引
private String newsDate;
}
public interface INewsDao extends PagingAndSortingRepository
public List<NewsEntity> findAllByNewsInfo(String info);
}
作业:秒杀系统没有命中的客户订单放入到ES——>时间+地区+购买的商品信息
在页面上可以实现全文搜索
服务治理八-日志治理
ELK
Logstash主要是用来负责搜集、分析、过滤日志的工具,支持大量的数据获取方式。一般工作方式为c/s架构,client端安装在需要收集日志的主机上,server端负责将收到的各节点日志进行过滤、修改等操作在一并发往elasticsearch上去。
ElasticSearch用来负责存储最终数据、建立索引和对外提供搜索日志的功能。它是个开源分布式搜索引擎,提供搜集、分析、存储数据三大功能。它的特点有:分布式,零配置,自动发现,索引自动分片,索引副本机制,restful风格接口,多数据源,自动搜索负载等。
Kibana是一个优秀的前端日志展示框架,它可以非常详细的将日志转化为各种图表,为用户提供强大的数据可视化支持。
系统日志功能
org.springframework.boot
spring-boot-starter-logging
logging:
file:
path: d:/log
level: #TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF
com.lovo.*: debug
@Slf4j //需要日志的地方
log.info(“testLog,日志”);
连接池:
认识连接池:因为创建连接本身就是一个耗时工作,即便是不进行数据交互。连接池是预先创建一部分连接进入连接池,然后管理连接池中连接的生命周期。
1、初始化连接数
2、增量数
3、最大连接数
4、空闲时间
5、最小连接数
6、连接等待时间
hikari:
minimum-idle: 5
# 空闲连接存活最大时间,默认600000(10分钟)
idle-timeout: 180000
# 连接池最大连接数,默认是10
maximum-pool-size: 10
# 此属性控制从池返回的连接的默认自动提交行为,默认值:true
auto-commit: true
# 连接池名称
pool-name: MyHikariCP
# 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
max-lifetime: 1800000
# 数据库连接超时时间,默认30秒,即30000
connection-timeout: 30000
connection-test-query: SELECT 1
服务治理九-认证
1、token来做单点登录
2、auth2.0
3、token ——>分布式的回话跟踪<———http协议是短连接无状态
4、会话跟踪: session 重新URL token(header)
练习:1、写一个认证系统实现登录,创建token
2、前端登录后把token放入到sessionStroe
3、前端访问订单系统、访问电影院系统,携带token去访问
4、电影院和订单系统对token进行认证,认证成功才返回数据
5、用户拥有2个权限-1为电影系统 2-订单系统
6、用户登录成功随机给用户分配一个权限
7、电影院或订单系统,在拦截器中获取到header中的token
8、先现在token是否合法,再验证用户是否拥有访问该系统的权限,如果通过放行返回数据,否则返回错误结果。
Nginx
1、web服务器
2、正向代理 —->网关
springcloud gateway 也是网关 如何选择?
如果需要用JAVA代码来写业务逻辑就要用gateway, 如果只是做路由是可以相互替换
3、反向代理 ——->负载均衡
主从分离
数据库的负载均衡
拆表
1、mycat中间件的配置—>server.xml
druidparser
</system>
<user name="root">
<property name="password">123456</property>
<property name="schemas">mycatDB</property>
</user>
表的配置:schema.xml
<schema name="mycatJ185" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1,dn2">
<!-- name 表名,物理数据库中表名
dataNode 表存储到哪些节点,多个节点用逗号分隔。节点为下文dataNode设置的name
primaryKey 主键字段名,自动生成主键时需要设置
autoIncrement 是否自增
rule 分片规则名,具体规则下文rule详细介绍
type 该属性定义了逻辑表的类型,目前逻辑表只有全局表和普通表。全局表: global 普通表:无
注:全局表查询任意节点,普通表查询所有节点效率低
autoIncrement mysql对非自增长主键,使用last_insert_id() 是不会返回结果的,只会返回0.所以,只有定义了自增长主键的表,才可以用last_insert_id()返回主键值。
mycat提供了自增长主键功能,但是对应的mysql节点上数据表,没有auto_increment,那么在mycat层调用last_insert_id()也是不会返回结果的。
needAddLimit 指定表是否需要自动的在每个语句后面加上limit限制,由于使用了分库分表,数据量有时候会特别庞大,这时候执行查询语句,
忘记加上limt就会等好久,所以mycat自动为我们加上了limit 100,这个属性默认为true,可以自己设置为false禁用。如果使用这个功能,最好配合使用数据库模式的全局序列。
subTables 分表,分表目前不支持Join。—>
<table name="sys_user" dataNode="dn1,dn2" rule="rule3" />
<!--
<table name="company" primaryKey="ID" dataNode="dn3,dn2,dn1" rule="mod-long"/>
<table name="goods" primaryKey="ID" type="global" dataNode="dn1,dn2" />
<table name="hotnews" primaryKey="ID" dataNode="dn1,dn2,dn3"
rule="mod-long" />
<table name="employee" primaryKey="ID" dataNode="dn1,dn2"
rule="sharding-by-intfile" />
<table name="customer" primaryKey="ID" dataNode="dn1,dn2"
rule="sharding-by-intfile">
-->
<!-- 1) childTable标签
id
func1
<tableRule name="rule2">
<rule>
<columns>id</columns>
<algorithm>func1</algorithm>
</rule>
</tableRule>
<tableRule name="auto-sharding-rang-mod">
<rule>
<columns>id</columns>
<algorithm>rang-mod</algorithm>
</rule>
</tableRule>
<tableRule name="jch">
<rule>
<columns>id</columns>
<algorithm>jump-consistent-hash</algorithm>
</rule>
</tableRule>
<function name="murmur"
class="org.opencloudb.route.function.PartitionByMurmurHash">
<property name="seed">0</property><!-- 默认是0 -->
<property name="count">2</property><!-- 要分片的数据库节点数量,必须指定,否则没法分片 -->
<property name="virtualBucketTimes">160</property><!-- 一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍 -->
<!-- <property name="weightMapFile">weightMapFile</property> 节点的权重,没有指定权重的节点默认是1。以properties文件的格式填写,以从0开始到count-1的整数值也就是节点索引为key,以节点权重值为值。所有权重值必须是正整数,否则以1代替 -->
<!-- <property name="bucketMapPath">/etc/mycat/bucketMapPath</property>
用于测试时观察各物理节点与虚拟节点的分布情况,如果指定了这个属性,会把虚拟节点的murmur hash值与物理节点的映射按行输出到这个文件,没有默认值,如果不指定,就不会输出任何东西 -->
</function>
<function name="hash-int"
class="org.opencloudb.route.function.PartitionByFileMap">
<property name="mapFile">partition-hash-int.txt</property>
</function>
<function name="rang-long"
class="org.opencloudb.route.function.AutoPartitionByLong">
<property name="mapFile">autopartition-long.txt</property>
</function>
<function name="mod-long" class="org.opencloudb.route.function.PartitionByMod">
<!-- how many data nodes -->
<property name="count">3</property>
</function>
<function name="func1" class="org.opencloudb.route.function.PartitionByLong">
<property name="partitionCount">2</property>
<property name="partitionLength">512</property>
</function>
<function name="latestMonth"
class="org.opencloudb.route.function.LatestMonthPartion">
<property name="splitOneDay">24</property>
</function>
<function name="partbymonth"
class="org.opencloudb.route.function.PartitionByMonth">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sBeginDate">2015-01-01</property>
</function>
<function name="rang-mod" class="org.opencloudb.route.function.PartitionByRangeMod">
<property name="mapFile">partition-range-mod.txt</property>
</function>
<function name="jump-consistent-hash" class="org.opencloudb.route.function.PartitionByJumpConsistentHash">
<property name="totalBuckets">3</property>
</function>
敏捷开发:
敏捷开发以用户的需求进化为核心,采用迭代、循序渐进的方法进行软件开发。在敏捷开发中,软件项目在构建初期被切分成多个子项目,各个子项目的成果都经过测试,具备可视、可集成和可运行使用的特征。换言之,就是把一个大项目分为多个相互联系,但也可独立运行的小项目,并分别完成,在此过程中软件一直处于可使用状态
1.墨刀-极简超快的移动应用原型工具
2.ProcessOn 在线作图工具,不用装Visio
3.Principle 前Apple工程师打造的交互设计工具,快速制作丰富流程的应用交互动画
4.摩客 —简洁高效的原型图设计工具
5.Sketch —一款轻量易用的矢量设计工具
6.Axure 老牌原型工具
7.xiaopiu 国内优雅高效的在线APP原型工具
8.Mockplus 支持全平台的快速原型设计工具
9.百度脑图 百度出品的一款良心在线的思维导图工具
10.principle主要做交互 集合了Sketch keynote flash等优点
出文档:
1、 需求文档(文字、图片、用例图)—-> 给客户看——->转换为概要设计
2、概要设计(程序员看)——->业务脚本(输入、输出、处理)——>业务流程图——>原型图
3、PD —->数据库物理模型
4、接口文档(远程调用的接口)
5、项目的规范
