笔记2
# 一.Spring Security 安全框架 权限控制> security网址https://gitee.com/zhao-qing-jing/msa2104/tree/master/02-jt-spring-security> 为什么选择SpringSecurity框架功能强大springBoot诞生后简化了配置
> 加密方式Bcrypt底层基于随机盐方式对密码进行hash不可逆加密MD5不可逆加密也能使用盐加密方式(盐值自己指定或者随机生成)> 1.简介 权限: 保护资源不被破坏安全框架> 2.项目初始化 maven 依赖: web security test配置: application.yml启动类: SecurityApplication运行: Using generated security password: 6f1adfb7-c350-4cee-9f67-d0f6363ff52clocalhost:8614/login: user 6f1adfb7-c350-4cee-9f67-d0f6363ff52c 登录操作
> 加了依赖之后, 启动项目, 访问就有登录界面> 3.简单认证 运行项目之后 Security 会产生一个密码 Using generated security password: 用来登录> 4.使用 > 登录后直接跳转到index.html登录之后的页面(登录之后就会跳转到index.html页面) static/index.html> 5.密码 程序自己生成:Using generated security password: 6f1adfb7-c350-4cee-9f67-d0f6363ff52c自己配置密码:spring:security:user:name: adminpassword: 8614配置自己加密后的密码:1. 启动类中写加密密码的方法encodePwd()2. 加密策略:String pwd = new BCryptPasswordEncoder().encode("8614");生成密码: $2a$10$WjRjID7zOIAQVt13txKqCe2UfsXnSOj3raun2pfpcIIy4RxXWh1sm3.把加密后的密码配置到配置类, 并恢复原始密码使加密后的密码恢复: {bcrypt}配置: password: '{bcrypt}$2a$10$WjRjID7zOIAQVt13txKqCe2UfsXnSOj3raun2pfpcIIy4RxXWh1sm'对密码进行匹配测试因为bcrypt加密方式是基于盐值对hash不可逆所以验证方式是 再一次对密码进行盐值加密, 再比较 加密后的密码String oldPwd = "8704";BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();String newPwd = encoder.encode(oldPwd);匹配测试 encoder.matches(原密码,加密后的密码)boolean matches = encoder.matches(oldPwd,newPwd);> MD5加密> 6.认证逻辑实践 1.配置类, 配置第三方 SpringSecurity SecurityConfig.java2.登录逻辑具体实现 @Service UserDetailsServiceImpl.java3.修改配置类 --登录页面(自己的) login.html3.1.框架自己的重定向 登录成功/失败之后页面重定向, security有自己的方法实现.defaultSuccessUrl("/index.html") .failureUrl("/login.html?error")3.2.框架转发 security是转发机制,基于post请求跳转到系统内部资源地址.successForwardUrl("/index") .failureForwardUrl()登录成功之后进行转发, 跳转的是工程内部资源(这里是controller中的 "/index")//spring mvc 中的重定向 return "redirect:/index.html";4.转发,处理器 自定义转发页面, 实现认证成功/失败的 *处理器*4.1.自定义转发登录成功页面 前后端分离, 自己定义 *登录成功* 以后的处理器, 进行页面跳转4.2.自定义转发登录失败页面 前后端分离, 自己定义 *登录失败* 以后的处理器, 进行页面跳转4.3.修改security配置类, 使用成功/失败的转发机制 处理器5.放行静态资源6.返回json数据配置类(配置Bean),业务逻辑(实现接口数据库查询用户信息封装返回),使用自定义登录界面(继承类重写方法配置要重定向页面信息),前后端分离(转发重定向使用控制器实现使用自定义主页面)访问流程:请求 -> Filters/AuthenticationManager -> AuthenticationProvider> 7.授权设计及实现 访问某个东西时, 你能不能访问1.配置类注解 @EnableGlobalMethodSecurity(prePostEnable=true)2.资源对象 ResourceController3.访问方法权限 @PreAuthorize("hasRole('ROLE_admin')")角色 @PreAuthorize("hasAuthority('sys:res:create')")权限4.自定义异常处理类4.1.访问需要认证的资源时,没有认证出现异常401,4.2.访问没有权限的资源是, 异常403,5.403 让配置类知道自定义异常处理类, 配置自定义异常处理 4035.1.异常返回JSON串 4036.401 让配置类知道自定义异常处理类, 配置自定义异常处理 4016.1.异常返回JSON串 401>8. 查数据库用户表, 角色表, 菜单表(权限)根据用户名username, 查询用户的信息1. 密码2. 权限>9. 用户登录成功之后信息存在哪里1. 会话 session/cookie 服务端创建了session 和 cookie (内存中) 把cookie(JSESSIONID)存储在客户端1.1.客户端与服务端通讯过程中产生的状态信息(类似会议记录),称之为会话状态2. 页面拿取用户信息3. http 超文本传输协议 无状态, 第一次与服务端交互服务端不知道是哪个客户端3.1.有状态会话 cookie session3.2.服务端把客户端请求的 *状态信息* 创建session并存储(识别是哪个客户端,属性有一个sessionId),3.3.创建cookie存储JSessionId(对应sessionId), 把cookie存储到客户端3.4.客户端再次请求, 会把cookie中的JSESSIONID给服务端, 服务端会在session中判断sessionId是否已经登录4.cookie浏览器存储的会话状态信息4.1.会话cookie, 浏览器关闭cookie结束4.2.持久cookie, 服务端创建cookie时 指定生命周期4.3.加密cookie,5.1. 这里的session/cookie是服务端的 认证5.2. 客户端的 SessionStorage 用于多个页面中的资源共享> 10. 服务端获取用户信息(登录成功之后)(从session中获取)Authentication authentication = SecurityContextHolder.getContext().getAuthentication() 获取认证信息authentication.getPrincipal() 得到用户对象信息 是User类型的 使用get~ 获取具体信息> 11. 单点登录系统request -> nginx -> {tomcat1,tomcat2,tomcat3}需求: 当登了tomcat1时, 之后 访问tomcat2或3 不再需要登录,每个tomcat都是会话session,问题: 1.tomcat之间session不能共享2. 浏览器默认不支持存储不同域的cookie信息解决: 1. 使session持久化, 服务端把tomcat写入 redis, 弊端:并发大时,redis访问压力增大2. 将用户的状态信息保存在客户端, 服务端不记录任何状态, 无状态会话服务端解析状态信息, 判断登录状态方案: 通票tomcat1 ---token---> nginx ---token---> clienttomcat2 解析 token (是能访问,不是不能访问)# 注解# 二.Apache shiro# 三.JWT技术> jwt网址https://gitee.com/zhao-qing-jing/msa2104/tree/master/03-jt-security-jwt> 一种规范的数据格式> 实现单点登录系统 中的 token加密>1.JSON Web Token JSON格式的web请求中的令牌, 数据的自包含, 安全信息传输, 数据传输过程中对数据进行加密 签名https://jwt.io/
>2.数据结构header(头部),payload(负载),signature(签名)xxxxx.yyyyy.zzzzz pXVCJ9.eyJzdWIiOiJodiaWF0IjoxNTE2MjM5MDIyfQ.1Cm7Ej8oIy1ZukEe84IIheader:元数据 : json格式 base64url算法原始令牌{"alg": "HS256", 签名算法指定"typ": "JWT" 令牌类型}使用base64url算法, 进行编码payload:实际需要传输的数据(token的), signature:对前两部分的签名, 防止数据篡改,指定秘钥(只有服务知道), 根据header中的算法产生签名,HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret) 拼接三部分header.payload.signature> 3. 单点登录系统:一个公司具有多个系统(需要登录)登录一个之后,其他的就不需要登录措施:redis(tomcat创建的session存储在redis中),token(tomcat返回给前端一个 令牌, 之后要登录的 拿令牌登录)> 4. jwt依赖: jjwt> 5. JWT技术 令牌1.JSON格式的web请求中的令牌2.数据结构: header.payload.signatureheader: 编码(加密), 令牌类型payload: 实际需要传输的数据(token 可以自己定义)signature: 签名3.登录成功创建tokenJwts.builder() 负载信息,签发时间,失效时间,秘钥(盐-只有服务端知道),生成token .compact();4.访问资源/再次进入网站 解析tokenJwts.parser() 设置秘钥(盐),解析负载信息,获取具体内容 .getBody()> 6. JWT工具类1.创建token2.解析token3.判断token是否失效> 7. 登录controller使用JWT工具类中的功能对登录进行验证, 返回token> 8. 访问资源controller登录之后才能访问> 9. 拦截器
>> SpringMVC 拦截请求, 访问资源controller之前执行的需求: 在拦截器里 检查用户是否已经登录过滤器 Filters拦截请求 DispatcherServlet拦截器 Interceptor HandlerInterceptorXxxController执行链 ExecutionChain Interceptor和XxxController拦截器: 在执行controller之前, 执行的功能过滤器: 在执行DispatcherServlet之前, 执行的功能1. 自己定义拦截器 实现 HandlerInterceptor接口2. 配置拦截器 spring mvc配置类 实现接口 WebMvcConfigurer> 10. jwtutils/**秘钥 盐*/private static String secret = "QWERTYUIOP";/*** 基于负载和算法 创建token信息*/public static String generatorToken(Map<String,Object> map){return Jwts.builder().setClaims(map).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis()+30*60*1000)).signWith(SignatureAlgorithm.HS256,secret).compact();}/*** 解析获取token*/public static Claims getClaimsFormToken(String token){return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();}/*** 判定是否失效*/public static boolean isTokenExpired(String token){return getClaimsFormToken(token).getExpiration().before(new Date());}# 四.浏览器session
sessionStorage 当前会话窗口
localStorage 持久-不同窗口会话也可以# 五.单点登录系统(sso)
https://gitee.com/zhao-qing-jing/msa2104/tree/master/04-jt-sso> web系统 --应用群一个业务分布在不同的tomcat上, 登录一个其他就不用登录
> 单系统cookie(同一个域), session
> 多系统> 聚合工程/项目 父子工程 可以复用之前的代码, 对项目中的资源进行统一管理, 多个项目moudle之间共享资源> 1. 启动类 main方法 参数 args启动时添加参数可以使用参数传参 Edit Configurations / Configuration / Environment> 2. springboot配置pom.xml application.yml @Configuration> 3. lambda表达式new接口时, 而且接口只有一个抽象方法new AuthenticationSuccessHandler() {@Overridepublic void onAuthenticationSuccess(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Authentication authentication) throws IOException, ServletException { }}(httpServletRequest,httpServletResponse,authentication) -> {}> 4. 公共部分1. 工程中, 两个model中有相同的代码(类), -- 进行提取 创建maven工程, 把相同部分添加到工程中 2. 使model中使用 common中的资源, model中添加common的依赖, 在model中pom中添加依赖, dependency 添加 指定包 > 5. 密码判断在哪里?临时: service中使用BCryptPasswordEncoder中的encode()方法, 使密码是加密后的本来: 从数据库中查询用户的密码(加密后的)service实现了UserDetailsService接口 security底层做了密码验证实现接口把用户名密码封装到User(security提供)中,返回 --user中封装了 用户名,加密后密码,权限 *** 返回给tomcat的session中存储 ***前端把 用户名,未加密密码 post方式传递过来,猜测: 后端把前端传递过来的 密码加密 和 user中的密码比较(或者把user中的密码解密 和 密码比较)结果执行 http.formLogin().SecurityConfig类中方法 configure() -参数: HttpSecurityHttpSecurity类中的方法 formLogin() 返回另一个方法getOrApply() -参数 new FormLoginConfigurer()FormLoginConfigurer类中方法 passwordParameter() 返回另一个 过滤器UsernamePasswordAuthenticationFilter中的方法 方法setPasswordParameter() -参数就是前端传递过来的密码过滤器UsernamePasswordAuthenticationFilter 中有默认的 /login post请求 username password# 5.1 单点登录子系统 设计与实现
> 1. authentication -- 产生token1. 返回客户端JSON WebUtils2. 认证 SecurityConfig -- 登录 成功200/失败500/没有认证(登录)4013. 令牌token JWTUtils -- 创建token 认证配置中, 登录/访问-返回json(使用WebUtils), 登录成功要返回客户端token(使用JWTUtils产生token)把token放到返回的JSONMap中4. 登录逻辑 UserDetailsServiceImpl -- 根据username查询(数据库)用户信息, user(Security的) 封装user信息(用户名,密码(数据库查的),权限),5. 用户密码验证,判断登录成功,SpringSecurity底层做了密码的验证> 2. resource -- 使用token1. 返回客户端JSON WebUtils2. 认证 SecurityConfig -- 没有访问权限403如果没有访问权限, 认证中使用返回JSON(WebUtils)有权限访问, 执行下面, ***** 这里两个tomcat之间共享token, HttpSecurity类中有关闭跨域攻击的方法, 认证和资源都关闭不同tomcat就能共享 *****3. 令牌token JWTUtils -- 解析token/超时判断, 解析了传进来的token, 得到用户和权限4. 访问资源handler ResourceController -- 一些访问资源5. SpringMvc拦截器 TokenInterceptor -- 在请求方法之前进行权限的验证, token中有没有访问权限 解析token, 把user信息重新封装到UserDetails(), username,password(设置为空就行 ""),authorities把封装的UserDetails保存到一个和security交互的对象(PreAuthenticatedAuthenticationToken)中, 再使用这个对象把解析的token和当前请求关联在一起, authenticationToken.setDetails(new WebAuthenticationDetails(request));把用户详情保存到SpringSecurity上下文中 6. 配置自定义拦截器 WebConfig7. controller类中方法添加了@PreAuthorize() 这个方法要有这个权限才能访问在权限配置类(SecurityConfig) 添加全局方法安全控制注解 -- @PreAuthorize() 才能起作用@EnableGlobalMenthodSecurity(prePostEnabled=true)> 3. common -- auth 和 resource 共性utils跨域配置> 4. ui -- 前端登录, 主界面点击按钮, axios请求后端, 后端返回数据, ui进行展示> 总结authentication 认证服务, 第一次用户登录时, 产生tokenresource 资源服务, 访问资源时, 使用token, (实现: 把解析的token中的user详细信息再次封装, 使用与security交互的对象--将详细信息和当前请求关联起来)> 遇到的问题1. 在配置security时没有关闭跨域攻击 -- 一直报没有访问权限的错误2. 再一次封装user详细信息时, 密码没有加 -- 报错500, 封装的user中password不能为空3. 拦截器返回false -- 客户端返回 1 4. 注解 @EnableGlobalMethodSecurity(prePostEnabled = true) 全局方法安全控制 --权限没起作用只有加了@EnableGlobalMethodSecurity(prePostEnabled=true) 那么在上面使用的 @PreAuthorize(“hasAuthority(‘admin’)”)才会生效> 实现: 根据用户名, 密码/权限 从数据库汇总查询出来mvc全局异常处理# 六.第三方登录 OAuth2# 七.微服务框架 Spring CLoud Alibabagateway网关, nacos注册中心, nginx负载均衡, zipkin链路监控, sentinel限流, redis内存数据库
##### 1. String.format() 拼接字符串String url = String.format("http://s%:s%/provider/doRestT/s%",ip,port,msg);
##### 2. @Bean此注解描述相关方法, 告诉spring此方法的返回值要交给spring管理, 名字, 利用@Autowired匹配值, 类型+名字, 先类型后名字
##### 3. nacos负载均衡, Ribbon负载均衡算法Ribbon服务调用
##### 4. 压力测试Jmter# 八.nacos 注册中心 Dynamic Naming and Configuration Service服务注册 发现 配置管理
> 各个服务之间的纽带, 多个服务之间联系 ????如何联系> 创建nacos数据库 nacos_config
> 修改配置文件 application.properties数据库
> 启动服务startup.cmd -m standalone## A 注册中心
## B 父子工程
## C 父工程管理依赖依赖版本: spring-cloud-dependencies spring-cloud-alibaba-dependencies
## D 子工程### 1. nacosnacos中的服务 存在 内存中心跳包, 如何判定服务是否还存在, 30秒### 2. provider 服务提供方依赖: web spring-cloud-starter-alibaba-nacos-discovery(nacos的注册和发现)nacos配置: Spring-application-name: sca-provider (服务名)spring-cloud-nacos-discover-server-addr: localhost:8848 (服务在注册中心 注册和发现)* 启动Nacos服务 启动provider服务 就能在nacos服务中服务列表发现 sca-provider服务### 3. consumer 服务消费方依赖 nacos配置 * 启动provider服务### 4. consumer 调用 provider * (第三方调用) *
#### 4.1 RestTemplate, 远程过程调用对象, 不需要nacos, 适合单服务之前调用RestTemplate -@Bean(spring没有提供,自己创建) @Autowired(使用时注入) 使用 远程过程调用对象, 基于此对象访问远程服务 方法: restTemplate.getForObject(url,String.class); -( url为要调用服务的url http://172.18.6.73:8614/provider/echo/ -( String.class 为响应数据类型
#### 4.2 nacos的负载均衡 LoadBalancedClient 基于RestTemplate需求: 一个服务请求另一个服务 操作 ip地址可变 http://172.18.6.73:8614/provider/echo/ RestTemplate实现太麻烦nacos中注册了服务, 从nacos中找到服务, -( consumer 从nacos拿到 provider服务列表 进行调用nacos负载均衡目的:访问不同的服务实现远程调用: RestTemplate总结: LoadBalancedClient获取nacos中的服务实例(本地算法-随机), RestTemplate实现远程调用 实现:注入: LoadBalancerClient获取nacos中的服务: loadBalancerClient.choose("sca-provider"); 得到ip port拼接得到url String.format("http://%s:%s/provider/echo/%s",host,port,"consumer服务-"+serverPort);RestTemplate远程调用 return restTemplate.getForObject(url,String.class);
#### 4.3 nacos的负载均衡 LoadBalancedC + RestTemplate 把RestTemplate实现负载均衡策略@Bean@LoadBalanced // 使这个对象具有 负载均衡public RestTemplate loadBalancedRestTemplate(){return new RestTemplate();}实现:注入: LoadBalancedRestTemplateurl: String.format("http://%s/provider/echo/%s", "sca-provider", "consumer服务-"+serverPort);调用: loadBalancedRestTemplate.getForObject(url,String.class);优点: 代码简洁缺点: 效率低(相比于直接使用LoadBalancedClient)原因-底层会拦截,拦截之后还是使用LoadBalancedClient获取服务实例
#### 4.4 Ribbon 负载均衡策略添加了依赖之后默认存在 Ribbon , 底层使用策略: -七种轮训策略随机策略
#### 4.5 Feign 方式远程调用声明式客户端,Web服务客户端实现:依赖: spring-cloud-starter-openfeign启动类: @EnableFeignClients // 启动feign方式远程服务调用, 扫描此注解描述的接口, 基于接口创建代理对象, 代理对象发起远程服务调用远程调用服务接口: RemoteProviderservice接口,不需要实现类(底层创建代理类)注解: @FeignClient 方法: 地址要和 调用的服务端一样 /provider/echo/{msg}具体调用哪个: @FeignClient(name="sca-provider",contextId="remoteProviderService")name: 标识调用哪个服务contextId: 唯一标识远程服务, Feign创建接口代理类时唯一标识这个代理类, 多个接口调用一个服务资源conroller: 注入接口, 使用接口的方法优点: 结构清晰, 重用性好异常:时间: feign方式调用服务, 不会等待时间很久, 配置等待时间@FeignClient(fallbackFactory=RemoteProviderFallbackFactory.class)定义异常处理的类 @Component 实现接口FallbackFactory<RemoteProviderService> 重写方法create 方法返回值为new 接口new RemoteProviderService() {}配置: application.yml中feign-hystrix-enable=true## E 配置中心服务的某些配置需要改动, 在nacos配置中配置, 服务就不用重启集中管理配置信息, 动态发布配置信息
### 1. 实现依赖: spring-cloud-starter-alibaba-nacos-config配置文件: bootstrap.yml 系统启动时读取配置中心的, bootstrap.yml的优先级比application.yml高spring: cloud: nacos:config: # 服务的配置server-addr: localhost:8848group: DEFAULT_GROUP # 分组配置 (平时一个配置, 双十一一个配置)file-extension: ymlnacos配置中心:配置列表添加配置, 注意DataId(要和服务名相同)从配置中心对应服务的配置中获取 logging级别
### 2. 日志需求: 调试代码中需要查看日志, 通过配置中心调整log的级别, (在项目正式上线之后, 测试日志不再输出)获取日志: LoggerFactory.getLogger(需要输出日志类名)日志级别: trace跟踪, debug, info, warn, error 低->高修改配置中心 配置, 服务自动刷新:@RefreshScope@SLF4J
### 3. 管理模型 nacos配置:dataId ${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file.extension}服务名 环境配置(测试环境, 开发环境) 数据格式nacos命名空间: dev-jt-scabootstrap.yml: nacos.config.namespace=7c540227-f344-4e30-bdfe-df11816e8811nacos分组配置: DEFAULT_GROUP_TWObootstrap.yml: nacos.config.group=DEFAULT_GROUP_TWOnacos共享配置: 提取配置中公共部分bootstrap.yml: # 九.spring cloud alibaba项目> 依赖版本 依赖关系
https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E# 十. sentinel链路监控
### 1. 描述系统负载过高, 采用限流,熔断策略
### 2. 启动sentinel-dashboard-1.8.1.jarjava -Dserver.port=8180 -Dcsp.sentinel.dashboard.server=localhost:8180 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.1.jarsentinel/sentinel
### 3. 项目配置依赖: spring-cloud-starter-alibaba-sentinel spring-boot-starter-actuatorapplication.yml: sentinel.transport.dashboard=8180 port=8719访问之后 在sentinel中 就会对访问进行监控
### 4. 实时监控对访问进行监控
### 5. 簇点链路consumer 访问 provider 时consumer的访问路径 /consumer/loadBC对此访问路径的操作:流控-对请求次数的限制, 降级, 热点, 授权
### 6. 流控QPS: 限制每秒请求次数 --超出次数..Blocked by Sentinel (flow limiting)线程数: 限制每秒线程数流控模式: 直接, 关联, 链路流控效果: 快速失败, Warm Up, 排队等待
#### 6.1 关联模式: 例如: 创建订单 查询订单 --使创建订单成功, 查询订单限流, 创建达到阈值查询限流关联资源达到阈值时, 把自己限流关联资源: 要访问的资源
#### 6.2 链路模式:多个服务对指定资源调用时, 超出阈值限流, 例如: 用户 调用订单, 订单 调用商品controller -> service实现: controller中调用service--@SentinelResource("doGetResource")ConsumerService类, @SentinelResource("doGetResource") 被调用的链路终点controller类, 中调用这个service, 形成链路入口资源:sentinel_spring_web_context 簇点链路的最高级
### 7. 降级, 熔断平均响应速度越来越慢, 经常出现异常Sentinel 熔断降级会在调用链路中某个资源出现 ***不稳定状态时***(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。
#### 7.1 慢调用比例表示链路请求数超过3时,假如平均响应时间假如超过200毫秒的有50%,则对请求进行熔断,熔断时长为10秒钟,10秒以后恢复正常实现: 不稳定状态 --线程安全//AtomicLong 类支持线程安全的自增自减操作private AtomicLong atomicLong=new AtomicLong(1);//获取自增对象的值,然后再加1long num=atomicLong.getAndIncrement();
#### 7.2 异常比例阈值-异常比例 0.1, 时长, 请求数
#### 7.3 异常数当资源近1分钟的异常数目超过阈值(异常数)之后会进行服务降级
### 8. 异常处理系统提供了默认的异常处理机制,假如默认处理机制不满足我们需求,我们可以自己进行定义。定义方式上可以直接或间接实现BlockExceptionHandler接口,并将对象交给spring管理。
### 9. 热点经常访问的数据, LRU算法- 统计最常访问的热点参数令牌桶- 实现:@GetMapping("findById")@SentinelResource("findId")public String doFindById(@RequestParam("id") Integer id){return "resource id is "+id;}簇点链路: sentinel_spring_web_context -> /consumer/findById -> findId 添加热点
### 10. 授权黑白名单定义请求解析器--黑白名单处理类 implements RequestOriginParser请求: http://ip:host/consumer/rest?origin=app1限制: origin的值app1 在黑名单中就限制了sentinel配置: 白名单/黑名单# 十一. gateway网关gateway filters sevice interceptor controller作用: 各种服务访问的入口, 并提供服务接收并转发所有内外部的客户端调用, 权限认证,限流控制
### 1. 实现: 单独的gateway服务依赖: spring-cloud-starter-gatewayapplication.yml配置: spring.cloud.gateway:routes: # 配置网关路由规则- id: route01 # 路由标识符, 路由id, 唯一的值# uri: http://localhost:8614/ # 网关转发的url consumer 请求 provider, 这里是provider的urluri: lb://sca-provider # 实现负载均衡predicates: # 匹配规则 断言,谓词- Path=/nacos/provider/echo/**filters: # 网关过滤器, 对谓词中的内容进行判断分析以及处理- StripPrefix=1 #转发之前去掉path中第一层路径,例如nacos 把谓词中的第一层路径去掉- id: route02discovery:locator: # 发现定位enabled: true # 开启通过服务名查找服务实例的特性 gateway在nacos中查找服务配置中可以有多个 routes.id (id 唯一) 指定多个路由地址spring.cloud.nacos.discovery.server-addr: localhost:8704
### 2. 总结诞生背景: 1) 统一服务访问的入口 2) 对系统服务进行保护 3) 镜像统一认证,授权,限流服务流程: F5(反向代理服务器-基于硬件实现) -> nginx(反向代理-基于软件实现,大量并发,网关的负载均衡) -> gateway(服务负载均衡) -> 微服务负载均衡: gateway负载均衡底层-Ribbon主要概念: 路由(id,uri), 断言, 过滤器503 :
### 3. 断言(谓词增强)定义路由转发的条件
#### 3.1 gateway内置断言工厂3.1.1 基于Datetime类型的断言工厂时间: AfterRoutePredicateFactory BeforeRoutePredicateFactory BetweenRoutePredicateFactorypredicates: # 并且关系- After=2021-08-01T23:59:59.789+08:00[Asia/Shanghai] # 时间之后可以访问- Before=2021-08-10T23:59:59.789+08:00[Asia/Shanghai] # 时间之前可以访问- Between=3.1.2 基于header的断言工厂HeaderRoutePredicateFactory判断请求Header是否具有给定名称且值与正则表达式匹配, 请求头中是否包含指定内容predicates:-Header=X-Request-Id, \d+3.1.3 基于Method请求方法的断言工厂判断请求类型是否跟指定的类型匹配predicates:-Method=GET # 只转发get请求3.1.4 基于Query请求参数的断言工厂判断请求参数是否具 有给定名称且值与正则表达式匹配predicates:-Query=pagesize, \d+
### 4. 过滤器增强谓词条件满足, 进入过滤器, 不满足报错404过滤器底层: Netty分类: GatewayFilter(单个路由) GlobalFilter(所有路由)规范: GatewayFilter接口4.1 局部过滤器4.1.1 基于AddRequestHeaderGatewayFilterFactory,为原始请求添加Header。filters:- AddRequestHeader=X-Request-Foo, Barcontroller中的请求方法可以拿到header中的数据4.1.2 基于AddRequestParameterGatewayFilterFactory,为原始请求添加请求参数及值,filters:- AddRequestParameter=foo, bar4.1.3 基于PrefixPathGatewayFilterFactory,为原始的请求路径添加一个前缀路径filters:- PrefixPath=/mypath4.1.4 基于RequestSizeGatewayFilterFactory,设置允许接收最大请求包的大小filters:- name: RequestSizeargs:# 单位为字节maxSize: 50000004.2 全局过滤器implements GlobalFilter, Ordered重写方法 -> 对请求进行过滤
### 5. 网关层面的限流sentinel参考地址: https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel依赖: spring-cloud-starter-alibaba-sentinel spring-cloud-alibaba-sentinel-gateway配置: sentinel:transport:dashboard: localhost:8180 #Sentinel 控制台地址port: 8719 #客户端监控API的端口eager: true #取消Sentinel控制台懒加载,即项目启动即连接sentinel的jvm参数: -Dcsp.sentinel.app.type=1# 十二. 重构sso cloud+auth+sso
### 12.1 Spring Framework 和 Spring BootSpring Framework: 是资源整合框架, 基于IOC思想进行资源整合 Spring Boot: 基于spring框架, 用于简化Spring框架整合资源的工程,同时为微服务工程创建和配置提供了更加便利条件### 12.2 依赖添加方式依赖版本控制方式<dependencyManagement><dependencies><!--Spring Boot--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.3.2.RELEASE</version><scope>import</scope><type>pom</type></dependency></dependencies></dependencyManagement>### 12.3 依赖
#### 1. 父工程依赖spring-boot-dependenciesspring-cloud-dependenciesspring-cloud-alibaba-dependencies## 12.4 业务
### 1. common1.1. 依赖: web(编译器有效)common不是独立的项目,作为其他子工程的依赖 1.2. 内容: WebUtil,
### 2. auth2.1. 依赖: web, security, jwt, mysql, mybatis, nacos discovery, nacos config2.2. 内容: 单点登录认证, 创建token, 解析token2.3. 配置: port, application.name, datasource, cloud(nacos-discovery,nacos-config), level, mybatis2.4. 启动类, pojo,dao,mapper,config(密码加密对象,认证),service(认证(用户名,密码)的具体实现(底层验证密码(前端和数据库的)),封装用户信息返回),util(创建token,解析token,判断token过期)
### 3. resource3.1. 依赖: web, srcurity, nacos(discovery,config), (feign)3.2. 内容: 访问的资源3.3. 配置: port, application.name, cloud nacos(discovery,config), logging3.4. 启动类 @EnableGlobalMethodSecurity(prePostEnabled = true)---Spirng方法级安全******* ,SecurityConfig, ResourceController, TokenInterceptor, WebConfig, 3.5. 拦截器 TokenInterceptor实现: 1) 这里判断token是否过期, 2) 解析token, 远程连接服务 RestTemplate Feign解决: 调用auth服务中的jwtUtil,--直接访问认证服务器, 使用RestTemplate或Feign1) 认证中心创建controller类让其他服务调用认证中心中的业务/auth/info 对此路径放行(-.antMatchers("/auth/info").permitAll()-)2) 资源服务 中修改拦截器, 访问认证中心得到数据(1) RestTemplate, 拦截器没有交给Spring管理, 所以我们自己注入值(构造方法)a. 在启动类中@Bean此对象(同时加上负载均衡@LoadBalanced)b. 拦截器注册配置类SpringWebConfig中注入@Autowired-RestTemplate, 注册 registry.addInterceptor(new TokenInterceptor(restTemplate)).addPathPatterns("/**"); // 要拦截的urlc. TokenInterceptor通过构造方法注入restTemplate, 使用restTemplateMap<String,Object> map = restTemplate.getForObject(url, Map.class);(2) Feigna. 启动类 添加注解 @EnableFeignClients (开启feign方式的服务调用)b. 远程认证服务调用接口 RemoteAuthService 注解: @FeignClient(name = "jt-sso-auth",contextId = "remoteAuthService")方法: getAuthentication(@RequestParam("token") String token);注解: @GetMapping("/auth/info") @GetMapping中的地址为jt-sso-auth服务中的一个地址c. TokenInterceptor构造方法注入 接口RemoteAuthService 调用方法Map<String, Object> map = remoteAuthService.getAuthentication(token);
### 4. gateway4.1. 依赖: nacos discovery,nacos config, gateway, 4.2. 内容: 通过网关访问auth, 4.3. 配置: port, application.name, cloud nacos(discovery,config), cloud gateway(routes,discovery),4.4. 启动类, 4.5. 网关配置auth服务: routes -id, uri:lb://jt-sso-auth4.5. 网关配置resource服务: routes -id, uri:lb://jt-sso-resource### 5. ui5.1. 依赖: web(tomcat)5.2. 内容: 页面5.3. 启动类, 页面5.4. 跨域问题:在 gateway 中解决跨域的问题 过滤器@Configuration-CorsFilterConfig 中@Bean-CorsWebFilter根据CorsWebFilter() 的参数找到需要那些值--进行配置# 权限控制(security)
# 单点登录(jwt)
# 微服务(cloud,nacos,gateway)# 十三. Redis
数据库概念 16个数据库 1个库2.5亿个key 1个key/value大小512M
没有表的概念
10万并发
3.1.2
### (1) 简介a. NoSql 非关系型数据库b. Redis是一个key-value存储系统(官网:http://redis.io),是一个分布式缓存数据库。c. 支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。d. redis集群
### (2) Mybatis-Cache 高速缓冲存储器a. 存储数据量比较小(因为没有考虑淘汰机制)b. 没有线程共享(一个线程的内部缓存)c. 缓存对象生命周期比较短
### (3) 命令a. redis进程 ps -ef | grep redis b. 进入容器 docker exec -it redisone bashc. 容器内连接redis --ip -h, port -p, password -a -u, username redis-cli -h 192.168.126.132 -p 6379 -a password -u usernamed. redis基础操作info-配置信息, clear, exit, shutdown, help e. 修改配置文件, 官网下载 https://redis.io/topics/configvi redis.conf查找 /requirepass下一个 n
### (4) 数据操作数据库概念 16个 0-15select 0 - 15 更改数据库 0-15set key valuetype key 数据类型get keykeys * 查看数据库内的 数据keyflushall 清除所有flushdb 清除当前ttl 查看key在生效时间内还有多次时间 -1(没有设置生效时长), -2(key已删除)
### (5) key有效时间设计a. expire 设置生效时长(秒)expire key secondsset name csdnexpire name 10ttl nameb. persist 取消时长设置persist keyc. pexpire 重新设置生效时间(毫秒)pexpire key milliseconds### (6) reids 常用数据类型字符串, 散列, 列表, 集合, 有序集合#### A. String-字符串a. 大小:512M --字数统计,追加日志,分布式自增id,点赞b. incr key --递增1 (key是整数)incrby key 增量 --指定增长系数c. decr key --递减1decrby key 减量 --指定步长递减d. append key value --追加值e. strlen key --字符串长度f. mset key value key value key valueg. mget key key key#### B. Hash-哈希类型 散列类型Redis散列类型相当于Java中的HashMap,实现原理跟HashMap一致,一般用于存储对象信息,存储了字段(field)和字段值的映射,一个散列类型可以包含最多232-1个字段。a. hset key field value 新增属性 并赋值hset user username zhao username是user的属性b. hget user username 获取属性c. hmset key field value [field value ...] 新增多个属性并赋值d. hmget key field [field...] 获取多个属性e. hgetall key keys user 获取key的所有属性f. hincrby key field 增量 属性值增加g. hexists key field 属性是否存在h. hdel key field 删除属性i. hkeys/hvals 只获取字段名/字段值#### C. List-链表Redis的list类型相当于java中的LinkedList,其原理就就是一个双向链表。 支持正向、反向查找和遍历等操作,插入删除速度比较快。经常用于实现热销榜,最新评论等的设计。一个列表最多可以包含232-1个元素(4294967295,每个表超过近43亿个元素)指针, 双向链表 单向链表a. lpush/rpush key element lpush mylist "A" 放数据 头部添加字符串元素添加: A B C D位置: D C B A 从头部添加索引: 0 1 2 3-4 -3 -2 -1b. lrange/rrange mylist 0 -1 取出所有元素 放数据, lpush-从右往左 rpush-从左往右取数据, lrange/rrange 对应放数据, 可以实现 栈(先进后出) 队列(先进先出)队列结构 lpush/rpop栈结构 lpush/lpoplrange ml 0 -1 展示所有lrange ml 0 -2 如果有三个元素c. lpop/rpop mylistlpop 从list的头部删除元素,并返回删除元素rpop 从list的尾部删除元素,并返回删除元素d. linsert mylist3 before "world" "there"在key对应list的特定位置之前或之后添加字符串元素e. lset mylist4 0 "four"设置list中指定下标的元素值(一般用于修改操作)f. lrem mylist5 2 "hello"从key对应list中删除count个和value相同的元素,count>0时,按从头到尾的顺序删除count<0时,按从尾到头的顺序删除count=0时,删除全部g. ltrim mylist8 1 -1保留指定key 的值范围内的数据h. llen mylistkey对应的长度i. lindex mylist5 0返回名称为key的list中index位置的元素j. rpoplpush从第一个list的尾部移除元素并添加到第二个list的头部,最后返回被移除的元素值,整个操作是原子的.如果第一个list是空或者不存在返回nilrpoplpush lst1 lst1rpoplpush lst1 lst2#### D. Set-集合Redis的Set类似Java中的HashSet,是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。Redis中Set集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。a. sadd name A ... 添加元素,重复失败b. smembers name 获取name内容c. spop name 随机移除并返回一个元素d. scard name 获取成员个数e. smove name sname zhao 把元素zhao从name中移动到sname中,移动一个元素到另外一个集合f. sunion name sname 并集#### E. 数据类型结构String set name zhao 1个key 1个valueHash hset user username zhao hmset key field value [field value ...] HashMap结构存储对象 1个key 多个field 1个属性1个value List lpush key element [element ...] LinkedList 1个key 多个elementSet sadd name member [member ...] HashSet 1个key 多个member数据库概念 16个数据库 1个库2.5亿个key 1个key/value大小512M没有表的概念Redis 中每个 hash/list/set 可以存储 2的32次幂 - 1 键值对(40多亿)。### (7) java中操作redis
#### A. 客户端 jedisz. APInew Jedis(ip,port);ping auth 密码set (String)getincrAPI 和 redis的命令行语句相同a. java中操作redis的一组apib. 依赖: jedis-redis.clients junitc. redis建立连接new Jedis("192.168.126.132",6379);d. 测试pingjedis.ping(); -> PONG报错: 连接不上原因: 网络问题,ip端口,redis初始配置解决: redis配置文件 --保护模式, --ip地址(只允许本地连接)protected-mode yes -> no 保护模式bind 127.0.0.1 ip代表只能本地连接e. 数据操作jedis.set("a","1");jedis.incr("a");jedis.get("a");jedis.strlen("a");jedis.expire("a", 10); //生效时长10sTimeUnit.SECONDS.sleep(10); //休眠10秒jedis.get("a");f. 关闭连接jedis.close()#### B. 客户端 jedis连接池 JedisPoola. 连接池 享元模式b. 连接池配置new JedisPoolConfig();jedisPoolConfig.setMaxTotal(1000); 最大连接数resourcejedisPoolConfig.setMaxIdle(60); 最大空闲时间c. 创建连接池 -根据连接池配置new JedisPool(jedisPoolConfig,ip,port);d. 从连接池中获取一个连接jedisPool.getResource();e. 对获取的连接进行数据操作resource.auth("123465");resource.set("class","cgb2104");resource.get("class");f. 关闭连接resource.close();关闭连接jedisPool.close();关闭连接池#### C. 模板 template常用于SpringBoot项目中 StringRedisTemplateRedisTemplate(序列化了)a.b. 依赖: spring-boot-starter-data-redisc. Spring提供的 操作redis数据库的字符串对象StringRedisTemplate获取连接: connection = stringRedisTemplate.getConnectionFactory().getConnection(); connection.ping();d. Spring提供的 操作redis数据库 复杂对象的对象RedisTemplatee. 自定义RedisTemplatehttps://blog.csdn.net/maitian_2008/article/details/119486215?spm=1001.2014.3001.5502### (8) Redis数据持久化 Rdb Aofa. shutdown --停掉redis服务通过redis-cli shutdown这种方式去停掉redis,其实是一种安全退出的模式,redis在退出的时候会将内存中的数据立即生成一份完整的rdb快照b. kill -9 进程号 --杀进程 ps -ef | grep redisyi.Rdba. 手动(save-阻塞式,bgsave-异步)开启或周期性保存b. 默认是开启的, 配置-redis.conf# 这里表示每隔60s,如果有超过1000个key发生了变更,那么就生成一个新的dump.rdb文件,就是当前redis内存中完整的数据快照,这个操作也被称之为snapshotting(快照)。save 60 1000# 持久化 rdb文件遇到问题时,主进程是否接受写入,yes 表示停止写入,如果是no 表示redis继续提供服务。stop-writes-on-bgsave-error yes# 在进行快照镜像时,是否进行压缩。yes:压缩,但是需要一些cpu的消耗。no:不压缩,需要更多的磁盘空间。rdbcompression yes# 一个CRC64的校验就被放在了文件末尾,当存储或者加载rbd文件的时候会有一个10%左右的性能下降,为了达到性能的最大化,你可以关掉这个配置项。rdbchecksum yes# 快照的文件名dbfilename dump.rdb# 存放快照的目录dir /var/lib/redis文件-dump.rdb会自动创建保存数据c. shutdown 停服务(安全模式停掉) redis 会将内存中的数据保存后退出,d. kill -9 进程 宕机redis内存中数据, 突然杀掉进程之后, 内存中的数据不会保存e. 手动调用 save-同步保存, bgsave-异步保存 执行rdb快照生成, Redis Save 命令执行一个同步保存操作,将当前 Redis 实例的所有数据快照(snapshot)以 RDB 文件的形式保存到硬盘。BGSAVE 命令执行之后立即返回 OK ,然后 Redis fork 出一个新子进程,原来的 Redis 进程(父进程)继续处理客户端请求,而子进程则负责将数据保存到磁盘,然后退出。f. rdb持久化机制 优缺点优点:第一:RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,这种多个数据文件的方式,非常适合做冷备,可以将这种完整的数据文件发送到一些远程云服务上去,在国内可以是阿里云的ODPS分布式存储上,以预定好的备份策略来定期备份redis中的数据.第二:RDB对redis对外提供的读写服务,影响非常小,可以让redis保持高性能,因为redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可。第三:相对于AOF持久化机制来说,直接基于RDB数据文件来重启和恢复redis进程,更加快速。缺点:快照间隔时间key的数量假如redis故障时,要尽可能少的丢失数据,那么RDB方式不太好,它都是每隔5分钟或更长时间做一次快照,这个时候一旦redis进程宕机,那么会丢失最近几分钟的数据。g. 持久化主动持久化 save. bgsave, shutdown被动持久化 redis.conf 配置文件中 save 60 1000 60s内10000个key发生变更, 会生成新的dump.rdb 快照--完整的数据快照 er. Aof日志中存储的是指令a. Aof方式是通过记录写操作日志的方式,记录redis数据的一种持久化机制。b. 默认是关闭的c. redis.conf配置文件# 是否开启AOF,默认关闭appendonly yes# 指定 AOF 文件名appendfilename appendonly.aof# Redis支持三种刷写模式:# appendfsync always #每次收到写命令就立即强制写入磁盘,类似MySQL的sync_binlog=1,是最安全的。但该模式下速度也是最慢的,一般不推荐使用。appendfsync everysec #每秒钟强制写入磁盘一次,在性能和持久化方面做平衡,推荐该方式。# appendfsync no #完全依赖OS的写入,一般为30秒左右一次,性能最好但是持久化最没有保证,不推荐。#在日志重写时,不进行命令追加操作,而只是将其放在缓冲区里,避免与命令的追加造成DISK IO上的冲突。#设置为yes表示rewrite期间对新写操作不fsync,暂时存在内存中,等rewrite完成后再写入,默认为no,建议yesno-appendfsync-on-rewrite yes#当前AOF文件大小是上次日志重写得到AOF文件大小的二倍时,自动启动新的日志重写过程。auto-aof-rewrite-percentage 100#当前AOF文件启动新的日志重写过程的最小值,避免刚刚启动Reids时由于文件尺寸较小导致频繁的重写。auto-aof-rewrite-min-size 64mbd. 文件appendonly.aofe. rewirte操作问题: 设置的key有失效时间,删除数据,清理, 内存中的key失效了, 但对应的写日志还在aof中,日志文件会越来越大内存中的数据 和 aof日志文件持久化的数据 不一致解决: aof会一定时间一定量数据执行rewrite操作, 针对当前内存中的数据构建新的日志, 保持跟redis内存中的数据一致f. 优缺点优点:第一:AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据.第二:AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复。第三:AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。因为在rewrite log的时候,会对其中的指导进行压缩,创建出一份需要恢复数据的最小日志出来。再创建新日志文件的时候,老的日志文件还是照常写入。当新的merge后的日志文件ready的时候,再交换新老日志文件即可。第四:AOF日志文件的命令通过易读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据.缺点:第一:对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大。第二:AOF开启后,支持的写QPS会比RDB支持的写QPS低,因为AOF一般会配置成每秒fsync一次日志文件,当然,每秒一次fsync,性能也还是很高的。第三:AOF这种基于命令日志方式,比基于RDB每次持久化一份完整的数据快照文件的方式,更加脆弱一些,容易有bug。不过AOF为了避免rewrite过程导致的bug,因此每次rewrite并不是基于旧的指令日志进行merge的,而是基于当时内存中的数据进行指令的重新构建,这样健壮性会好很多。g. 如何选择redis的持久化方式?第一:不要仅仅使用RDB,因为那样会导致你丢失很多数据。第二:也不要仅仅使用AOF,因为AOF做冷备没有RDB做冷备进行数据恢复的速度快,并且RDB简单粗暴的数据快照方式更加健壮。第三:综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择; 用RDB来做不同程度的冷备。### (9) 事务处理实践默认事务处理: 乐观锁处理机制, 某一时刻都可以更新,但只有一个更新成功, 不会阻塞a. 命令开启事务 multi 结束事务 exec 取消事务 discard监控key watch去掉监控 unwatch### (10) 高级特性
> 1. redis主从复制a. 需求: 多个redis 提高redis并发能力b. 设计: 通过架构设计 协同多个redisc. 架构: 1主多从 --1个master 多个slave --读操作在slave上,写操作在master上 (读操作 比 写操作 多)d. 拷贝redis配置文件 cp -r /root/mytest/redis/one/ /root/mytest/redis/twoe. 角色: 开启的redis容器服务 角色都是master6379: info replicationf. 设置Master/Slave架构: 设置两个redis容器服务为slave master 6379 slave 6380 6381docker inspect redisone6379 IPAddress: 172.17.0.26380/6381: slaveof 172.17.0.2 6379h. 读写:6379 可读可写6380/6381 只读A. 主从同步原理Redis的主从结构可以采用一主多从或者级联结构,Redis主从复制可以根据是否是全量分为全量同步和增量同步。a.全量同步Redis全量复制一般发生在Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份。具体步骤如下:1)从服务器连接主服务器,发送SYNC命令;2)主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;3)主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;4)从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;5)主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;6)从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;b.增量同步Redis增量复制是指Slave初始化后,开始正常工作时主服务器发生的写操作同步到从服务器的过程。 增量复制的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。B. 问题a.如果redis要支持10万+的的并发你会怎么做?-- 主从架构, 读写分离 --单机的redis几乎不太可能说QPS超过10万+,除非一些特殊情况,比如你的机器性能特别好,配置特别高,物理机,维护做的特别好,而且你的整体的操作不是太复杂,一般的单机也就在几万。真正实现redis的高并发,需要读写分离。对缓存而言,一般都是用来支撑读高并发的,写的请求是比较少的,可能写请求也就一秒钟几千。读的请求相对就会比较多,例如,一秒钟二十万次读。所以redis的高并发可以基于主从架构与读写分离机制进行实现。b.Redis的replication机制是怎样的?(1)redis采用异步方式复制数据到slave节点。(2)一个master node是可以配置多个slave node的。(3)slave node也可以连接其他的slave node。(4)slave node做复制的时候,是不会block master node的正常工作的。(5)slave node在做复制的时候,也不会block对自己的查询操作,它会用旧的数据集来提供服务; 但是复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务了。(6)slave node主要用来进行横向扩容,做读写分离,扩容的slave node可以提高读的吞吐量。C. redis 有密码, 主从架构中的slave 需要设置master-passwordredis密码redis.conf中 requirepass 123456config set requirepass 123456, auth 123456, config get requirepassslave连接master(有密码)redis.conf中 masterauth 123456D. 关闭服务a. 关闭master服务, 重启后还能与slave连接b. 关闭slave服务, 重启之后需要 重新配置为slave slaveof 172.17.0.2 6379> 2. redis哨兵模式A. master宕机之后, 重新选一个 master 由一个或多个Sentinel实例(instance)组成的Sentinel系统(system)可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。B.实现 --分别在主从redis容器内部配置(1)文件: 配置 /etc/redis sentinel.confsentinel monitor redisone6379 172.17.0.2 6379 1其中, 如上指令表示要的监控的master, redis6379为服务名, 172.17.0.2和6379为master的ip和端口,1多少个sentinel认为一个master失效时,master才算真正失效.(2)执行: 每个容器内sentinel.conf所在位置redis-sentinel sentinel.conf(3)高阶配置 sentinel.confsentinel monitor redisone6379 172.17.0.2 6379 1 daemonize yes #后台运行logfile "/var/log/sentinel_log.log" #运行日志sentinel down-after-milliseconds redis6379 30000 #默认30秒后选masterC.哨兵工作原理分析1):每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他 Sentinel 实例发送一个 PING 命令。2):如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值(这个配置项指定了需要多少失效时间,一个master才会被这个sentinel主观地认为是不可用的。 单位是毫秒,默认为30秒), 则这个实例会被 Sentinel 标记为主观下线。3):如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。4):当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线 。5):在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有Master,Slave发送 INFO 命令 。6):当Master被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次 。7):若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会被移除。8): 若 Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除。a. 问题: 容器内没有vi vim bash: vi: command not foundapt-get update apt-get install vimb. echo回显echo sentinel monitor redisone6379 172.17.0.2 6379 1 >> sentinel.confdocker run -p 6379:6379 --name redisone6379 \-v /root/mytest/redis/one/data:/data \-v /root/mytest/redis/one/conf:/etc/redis \-v /root/mytest/redis/one/log:/var/log \-d redis redis-server /etc/redis/redis.confdocker run -p 6380:6379 --name redistwo6380 \-v /root/mytest/redis/two/data:/data \-v /root/mytest/redis/two/conf:/etc/redis \-v /root/mytest/redis/two/log:/var/log \-d redis redis-server /etc/redis/redis.confdocker run -p 6381:6379 --name redisthree6381 \-v /root/mytest/redis/three/data:/data \-v /root/mytest/redis/three/conf:/etc/redis \-v /root/mytest/redis/three/log:/var/log \-d redis redis-server /etc/redis/redis.confcp /root/mytest/redis/one/conf/sentinel.conf /root/mytest/redis/three/conf/sentinel.conf> 3. redis集群高可用A.概述Redis集群架构实现了对redis的水平扩容,即启动N个redis节点,将整个数据分布存储在这N个redis节点中,每个节点存储总数据的1/N。redis集群通过分区提供一定程度的可用性,即使集群中有一部分节点失效或无法进行通讯,集群也可以继续处理命令请求。B.架构对于redis集群(Cluster),一般最少设置为6个节点,3个master,3个slave,其简易架构如下:C.创建集群(1)网络环境 --用于redis-cluster能于外界进行网络通信,一般常用桥接模式。docker network create redis-netdocker network lsdocker network inspect redis-net(2)redis配置模板mkdir -p /root/mytest/redis/redis-clustercd /root/mytest/redis/redis-clustervim redis-cluster.tmpl(3)redis-cluster.tmpl内容port ${PORT}cluster-enabled yescluster-config-file nodes.confcluster-node-timeout 5000cluster-announce-ip 192.168.126.132cluster-announce-port ${PORT}cluster-announce-bus-port 1${PORT}appendonly yesport:节点端口,即对外提供通信的端口cluster-enabled:是否启用集群cluster-config-file:集群配置文件cluster-node-timeout:连接超时时间cluster-announce-ip:宿主机ipcluster-announce-port:集群节点映射端口cluster-announce-bus-port:集群总线端口appendonly:持久化模式(4)redis-cluster.tmpl所在目录执行命令 创建配置文件for port in $(seq 8010 8015); \do \mkdir -p ./${port}/conf \&& PORT=${port} envsubst < ./redis-cluster.tmpl > ./${port}/conf/redis.conf \&& mkdir -p ./${port}/data; \done(5)创建集群中的redis节点容器for port in $(seq 8010 8015); \do \docker run -it -d -p ${port}:${port} -p 1${port}:1${port} \--privileged=true -v /root/mytest/redis/redis-cluster/${port}/conf/redis.conf:/usr/local/etc/redis/redis.conf \--privileged=true -v /root/mytest/redis/redis-cluster/${port}/data:/data \--restart always --name redis-${port} --net redis-net \--sysctl net.core.somaxconn=1024 redis redis-server /usr/local/etc/redis/redis.conf; \done(6)创建redis-cluster集群配置docker exec -it redis-8010 bashredis-cli --cluster create 192.168.126.132:8010 192.168.126.132:8011 192.168.126.132:8012 192.168.126.132:8013 192.168.126.132:8014 192.168.126.132:8015 --cluster-replicas 1(7)连接redis-cluster,并添加数据到redisredis-cli -c -h 192.168.227.131 -p 8010> 4. Redis的高并发跟整个系统的高并发是什么关系?第一:redis,你要搞高并发的话,不可避免,要把底层的缓存搞得很好。例如,mysql的高并发,是通过一系列复杂的分库分表,订单系统,事务要求的,QPS到几万,比较高了。第二:要做一些电商的商品详情页,真正的超高并发,QPS上十万,甚至是百万,一秒钟百万的请求量,只有redis是不够的,但是redis是整个大型的缓存架构中,支撑高并发的架构里面,非常重要的一个环节第三:你的底层的缓存中间件,缓存系统,必须能够支撑的起我们说的那种高并发,其次,再经过良好的整体的缓存架构的设计(多级缓存架构、热点缓存),支撑真正的上十万,甚至上百万的高并发。# 十四. enum 枚举
### 1) 枚举类型 enum --更加严格约束变量类型enum Gender{MALE,FEMALE,NONE;public void toStr(){}}class Product{private Gender cap = Gender.MALE;}
### 2) 休眠 TimeUnit.SECONDS.sleep(10); //休眠10秒TimeUnit 枚举类型SECONDS 枚举中的实例sleep 底层是Thread.sleep()# 十五. java对象 和 json串 互转三剑客: fastjson, jackson, gsonA. gsona. 依赖 gson com.google.code.gsonb. gson.toJson(mapString)c. gson.fromJson(blog, Map.class)# 十六. 队列A. 非阻塞队列 --空了还可以取redis list 的rpopB. 阻塞队列 --空了不能取redis list 的brpop# 十七. Spring工程找启动类 测试类找启动类main/java中的包结构 com.cy.sys.Applicationtest/java中的包结构 com.cy.sys.Applciation两个包结构要一样报错: @SpringBootConfiguration# 十八. Spring Mvc依赖: spring-boot-starter-webweb依赖内嵌了一个tomcat服务, 这个服务遵循javaee规范实现的, 内置了对Servlet, Listener, Filter技术的支持# 十九. ui启动使用lite-server快速搭建服务器作用快速搭建服务器自动创建各静态目录### 初级玩法进入项目根目录,执行下列步骤 :安装lite-server :npm initnpm install --save-dev lite-server在package.json中添加启动命令"scripts": {"dev": "lite-server"},则运行 npm run dev(或直接lite-server)lite-server会自动找到index.html并运行### 中级玩法新建配置文件bs-config.jsonbs-config.json中可以:指定监听的端口号,指定要启动的浏览器,browser是一个数组,可以添加多个浏览器指定要监视的文件{"port":8084,"browser" : ["chrome"]}### 高级玩法新建配置文件bs-config.js,但是需要删除前面的bs-config.json"use strict";module.exports = {"port":8084,"browser" : ["chrome"],"server": {middleware: {// overrides the second middleware default with new settings1: require('connect-history-api-fallback')({index: '/index.html',verbose: true,}),},},};# 二十. java中操作redis# 使用java操作redis
## yi,jedis 客户端z. APInew Jedis(ip,port);pingauth 密码set (String)getincrAPI 和 redis的命令行语句相同a. java中操作redis的一组apib. 依赖: jedis-redis.clients junitc. redis建立连接new Jedis("192.168.126.132",6379);d. 测试pingjedis.ping(); -> PONG报错: 连接不上原因: 网络问题,ip端口,redis初始配置解决: redis配置文件 --保护模式, --ip地址(只允许本地连接)protected-mode yes -> no 保护模式bind 127.0.0.1 ip代表只能本地连接e. 数据操作jedis.set("a","1");jedis.incr("a");jedis.get("a");jedis.strlen("a");jedis.expire("a", 10); //生效时长10sTimeUnit.SECONDS.sleep(10); //休眠10秒jedis.get("a");f. 关闭连接jedis.close()## er,jedis连接池-JedisPoola. 连接池 享元模式b. 连接池配置new JedisPoolConfig();jedisPoolConfig.setMaxTotal(1000); 最大连接数resourcejedisPoolConfig.setMaxIdle(60); 最大空闲时间c. 创建连接池 -根据连接池配置new JedisPool(jedisPoolConfig,ip,port);d. 从连接池中获取一个连接jedisPool.getResource();e. 对获取的连接进行数据操作resource.auth("123465");resource.set("class","cgb2104");resource.get("class");f. 关闭连接resource.close();关闭连接jedisPool.close();关闭连接池## san,template 模板/*** 此对象为Spring提供的操作redis数据库中 字符串的一个对象*/@Autowiredprivate StringRedisTemplate stringRedisTemplate;/** Ping */public String testPing(){RedisConnection connection = stringRedisTemplate.getConnectionFactory().getConnection();String ping = connection.ping();return ping;}/*** 基于对象 StringRedisTemplate 操作字符串*/public String testStringOperation(){// 字符串操作对象ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();// redis存储数据valueOperations.set("name","qwert");// 更新redis中数据// valueOperations.increment("name");// 获取数据String name = valueOperations.get("name");return name;}# 二十二. sso-redis/*** session{username,password,expired}** 1. 访问redis, 检查是否有有效会话信息* isValidSession() --没有有效会话信息, 判断是否登录超时* 2. 没有有效会话信息, 创建会话对象存储到 redis(用户,有效时间,)* login()*/public class SsoRedis {public static void main(String[] args) {req(1);req(2);req(3);}/*** 访问*/public static void req(Integer time){System.out.println("==访问系统资源,登录,session==");System.out.println("第"+time+"次访问");boolean flag1 = isValidSession();if (flag1){System.out.println();System.out.println("直接访问");}else {login("qing","123456");System.out.println("登录成功,请访问");}}/*** 校验session的有效性*/public static boolean isValidSession(){Jedis jedis = new Jedis("192.168.126.132", 6379);Map<String, String> session = jedis.hgetAll("session");if (session==null||session.size()==0){System.out.println("还没有登录");jedis.close();return false;}String expiredStr = session.get("expired");if (expiredStr==null||"".equals(expiredStr)){System.out.println("登录超时");jedis.close();return false;}Date expired = new Date(Long.parseLong(expiredStr));if (expired.before(new Date())){System.out.println("登录超时");jedis.close();return false;}return true;}public static void login(String username,String password){String token = UUID.randomUUID().toString().replace("_", "");Calendar calender = Calendar.getInstance();calender.add(Calendar.MINUTE,60);Map<String,String> map = new HashMap<>();map.put(token,username);map.put("expired",String.valueOf(calender.getTimeInMillis()));Jedis jedis = new Jedis("192.168.126.132", 6379);jedis.hset("session", map);jedis.close();}}
笔记1
# 2021-04-02 ----------------------------
# Spring Cloud Alibaba
# jingtao# 若依 ruoyi.vip
> 微服务
> sentinel> Redis
* 在 redis 根路径执行(默认端口 6349)
* 运行 redis-cli -h 127.0.0.1 -p 6379
> 安装 Nacos 服务治理业务
* 改/application.properties
> clone RuoYi-Clond 项目
* 创建需要的数据库
> 启动Nacos服务
* 在nacos目录中的bin目录下 cmd
* 运行startup.cmd -m standalone (单击方式,非集群版)
* ht tp://localhost:8848/nacos
> nacos中 修改 redis mysql 的用户名密码
* ruoyi-gateway-dev.yml
* ruoyi-auth-dev.yml
* ruoyi-system-dev.yml 修改数据库name password
> 启动若依服务
* RuoYiGatewayApplication
* RuoYiAuthApplication
* RuoYiSystemApplication
* ruoyi-ui 右键 open in Terminal(终端 目的:启动若依前端服务)
* Terminal:local 运行 npm install 和 npm run dev (前提已安装nodejs 版本要合适)>>>>>
* nacos 阿里的
* ruoyi-cloud 若依微服务项目# 2021-04-06 ----------------------------
# JVM
* 是一种规范 它有很多产品
> 命令行
* java -varsion (什么jvm)
* set java_ home (检查JAVA_HOME)
* mysql -uroot -proot (登录数据库)
* status 登录数据库后(查看数据库版本)
* cd .. (上一级目录)
* mvn -v 在maven/bin 目录中cmd (查看mvn版本)
* node -v cmd运行(查看node版本) npm -v
* mysqldump -uroot -proot ry-config>d:/ry-config.txt (导出数据库表)* 杀进程 端口号# 分布式概念
> 高并发架构
* 分布式 系统,数据库,Tomcat
* 高可用 5个9衡量标准 断电-(ups电源,不同地点(城市,国家)部署)弹性设计
* 集群
* 负载均衡
* 正向代理和反向代理
> 单体架构
* 域名 ip 服务器 tomcat(port 进程)
* 所有的服务 库在一台电脑上
> 服务与库分开
*
> 本地缓存 分布式缓存
* 浏览器缓存 本地缓存 分布式缓存
* jvm缓存
* mybatis 中的cache二级缓存可用的清除策略 https://mybatis.org/mybatis-3/zh/sqlmap-xml.html#cache
* 一级缓存, 二级缓存一级缓存 指sqlsession级别缓存二级缓存 >>>>123
* UPS
* IBM
> ----------
* mysql -uroot -h localhost -p 通过ip地址登录远程数据库-h localhost 本地库 -h 指host 域名 % 为允许所有域名-h 10.1.6.82 远程库ip地址的库
* 数据库创建用户create user 'cloud'@'%' identified by 'cloud';
* ping 172.18.35.222 检测能否访问关防火墙, 放开3306端口
* 授权限 grant all on *.* to 'cloud'@'%' 所有的权限 第一个*库 第二个*表
* ? createuser
>---------
* CAP原则
* LruCache
* Tomcat
* FIFO算法 First In First Out 添加顺序
* LRU算法 访问不被gc 访问顺序# 2021-04-07 ----------------------------
> 本地缓存
* Cache -new MapCache() --使用 new SoftHashMap()
> Reference
* 引用 Bean使用强引用
* 强引用(此引用引用的对象即使内存不足也不会被GC)
* 软引用(允许在内存不足时清除软引用引用的对象) SoftReference --提高命中率
* 弱引用(在GC触发时,运行清除弱引用引用的对象) WeakReference --内存不足时
> 缓存中使用引用 GC时对数据的清除
* FIFO LRU --缓存满的时候gc
> 任务调度
* 时间延迟再执行> 在数据层添加缓存
* 执行查询 第一次在数据库查询
* 第二次在缓存中查询
? 查询库中没有的数据 先执行select count(0) 返回total为1(1是一条记录)
? 没有查询到记录第二次在缓存中查询时还有命中率 --查询结果为null放在了缓存中> mybatis 缓存
* 一级缓存 BaseExcutor
* 二级缓存 CachingExcutor
* 设计模式: 装饰模式(油漆工模式 一层装饰一层 使用在mybatis中的二级缓存)
* 先二级缓存后一级缓存 二级缓存中有数据时,不找以及缓存
* 查找顺序 : 先找mybatis中的二级缓存 再找一级缓存 没有再找数据库
* 分布式缓存可以看做三级缓存> 负载均衡
* 多个tomcat处理请求
* 客户端的负载均衡 --不可用, 把端口直接暴露给用户> 反向代理 Nginx (在接入层设计时)
* 轮循的算法 --for循环> ? > 如何把请求给多个tomcat(处理并发)
* 客户端轮询 服务端轮询
* 权重
* 比重# 一个框架有自己的算法, 需要有接口, 使我们自己来写自己的算法> 当缓存中没有数据时 需要在数据库中读,写 分库设计
* 并发量高时 数据库扛不住并发
* 解决: 把数据库的读写分开
* Mycat 数据库中间件> 大表分小表 一个表500万条数据> 水平扩展 水平切分
* 多个tomcat 解决并发
* 多个数据库 读 写 提高性能
* 多个表 按时间 id > Nginx 负载均衡
* LVS(软件)/F5(负载均衡硬件)> master/slave
* 主从分布式架构系统> 大应用拆分小应用> 微服务
* 应用 服务中共性的模块 抽离 形成新的*单独(独立)*的服务> DevOps 开发运维一体化# 微服务 MSA
spring.io# Nacos
* 是一个应用于服务注册与发现、配置管理的平台。
* startup.cmd -m standalone
* 技术: springboot spring springmvc - springweb spring-jdbc 连接数据库spring 中的security 授权> jar包运行
java -jar 文件名# 2021-04-08 ----------------------------
> cmd执行java程序
javac -d . Hello.java 编译文件
java com.cy.lvjing 执行文件
> jar包 打包
cmd - jar> 服务注册与调用
服务提供者
服务消费者
* 两者都需要注册到 NacosServer> idea高并发
configurations -> Allow parallel run# 2021-04-09 ----------------------------
>角色
* 服务提供者
* 服务消费者
* 注册中心
> 如何注册到nacos服务的
* 基于http请求# 高可用
* 持续的提供服务> nacos注册中心关闭, 服务消费方还能调用服务
* 注册中心会有本地缓存
? 如何拿到注册中心的提供方实例
* nacos推送 ->注册中心基于UDP协议推送 UDP协议(数据包)
* HTTP请求 底层TCP协议
> Nacos的高可用性
* 重试
* 心跳
* 缓存
* 集群> HTTP
> TCP
> UDP> 消息的推拉模式>RestTemplete
一个 HTTP 请求工具,它提供了常见的REST请求方案的模版,# 2021-04-12 ----------------------------
> sentinel
* 限流熔断 -?在网站流量(访问量)过大时,保证各业务的安全运营,系统在任何情况下都不会崩溃 -.采用限流, 降级, 熔断 保护系统-,流量控制中间件
* 阿里开源的有 核心功能, 还有边缘接口> sentinel控制台 github.com/alibaba/Sentinel/releases
* .jar文件 根目录java -jar执行 可写参数
* tomcat服务 指定在8180端口> Sentinel 限流熔断
* 保护服务的稳定性, 高可用性* sentinel-dashboard-1.8.0.jar
* 执行文件 根目录cmdjava -Dserver.port=8180 -Dcsp.sentinel.dashboard.server=localhost:8180 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jarjava -Dserver.port=8180 -Dcsp.sentinel.dashboard.server=localhost:8180 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar
* 服务消费方 nacos-consumer Sentinel业务端
* 在消费方添加sentinel依赖, * 需要和客户端交流
* 配置端口进行 与客户端交流> 限流
* --簇点链路--流控--
* QPS 每秒访问次数 每秒请求数量
* 单击阈值 1 代表每秒只能访问一次> 心跳
>
> 流量
> > # 2021-04-13 ----------------------------
> sentinel 阿里推出的流量控制平台,防卫兵 -用户进行url访问的数量 --启动jar文件 是一个springboot程序 内置tomcat服务jmeter专门做压力测试> sentinel 限流原理:
* 规则配置在sentinel(dashboard) 推送规则(通过端口 8719) 依赖添加在消费方(spring-cloud-start-alibaba-sentinel)jar包
* 访问url(程序为springmvc框架 通过DispatcherServlet) 通过拦截器(HandlerInterceptor) 拿到规则 进行限流操作
* sentinel-dashboard 和 web app 通过restTemplate请求进行访问> RestTemplate
* > 熔断 是把服务停掉
> 降级 degrade
* RT ResponseTime
* 请求数5 比例阈值0.5 最大RT1 熔断时长5 5个请求的50% 响应时间超过1秒发生熔断5秒
* * 限流或降级都会抛出异常 并进行异常处理 降级异常父类BlockException
* DefaultBlockExceptionHandler 异常处理器 降级DegradeException
* 自己写的异常处理类 ServiceBlockExceptionHandler 谁调用(断点查看) -springmvc 拦截器> 解释执行 -执行一次
> 频繁执行 -热点代码
* JVM JIT即时编译 > 热点 -经常访问的数据
* 热点数据限流 ParamFlowException> sentinel模式支持的持久化有哪些 DataSourcePropertiesConfiguration> 系统规则
* > 授权规则
* > sentinel规则持久化
* # 2021-04-14 ----------------------------dev 开发环境
线上
运维> nacos 应用实践 配置
...软件中的配置信息 配置中心管理配置信息 -不用重启服务也会更新配置
*
... # 2021-04-15 ----------------------------
> feign方式调用 远程服务调用* feign是声明式的web service客户端,它让微服务之间的调用变得更简单了,类似controller调用service。Spring Cloud集成了Ribbon和Eureka,可在使用Feign时提供负载均衡的http客户端。> ribben 服务负载均衡> 微服务 api中使用了feign远程调用 在notice启动要使用远程@EnableFeignClients服务不然会出现远程调用接口no bean> 使用注解@RequiredLog* 在公告notice方法上添加此注解就可以进行日志的添加 > -0-----------------------0-
>1. 微服务项目结构
> 00-sca * ms-api -feign接口+pojo/dto feign方式调用. ms-log-api * ms-common -aspect,util,interceptor,aop 公共资源. ms-log-common* ms-modules -微服务 . ms-log . ms-nacos >2. 依赖:
* spring放在03父中 mysql,jdbc,mybatis,web,pagehelper插件,AOP,devtools热部署,lombok,
* modules alibaba-nacos,alibaba-sentinel,sentinel流控 . ms-nacos (aop-03,) ?资源依赖于common-加ms-log-common依赖 . ms-log
* common . ms-log-common () ?资源依赖于api-加ms-log-api依赖
* api openfeign,(web-03) . ms-log-api >3. 业务
> ? notice调用log服务 _记录日志_
* 通过aop调用 通过feign方式 notice依赖common common依赖api> api feign方式的调用* pojo. 属性,序列化接口,get/set* service接口 远程调用. 保存日志,访问url,feign方式> common aop 如何调用api* 注解* aspect* 请求远程调用-异步 写日志要异步写入- > ms-log* 启动类 -要异步* 发送请求controller* 配置 bootstrap.yml* _业务_> ms-notice* 启动类 -要feign远程* 发送请求controller* 配置 bootstrap.yml* _业务_>4. 业务怎么实现* notice服务 log服务 nacos作为服务注册中心 -1.log进行注册 notice发现log服务 -2.通过feign方式调用 * 访问notice-url -1.notice查询添加了@RequiredLog注解 aop方式 -2.进行异步添加日志,feign方式调用log中的controller-service-dao * 微服务中 nacos作为服务消费方 log作为服务提供方 * aop modules--notice查询方法中加注解(aop添加日志) common--注解 切入点 异步远程调用添加日志 api--添加日志
.?. 远程调用怎么log中添加日志>5. nacos配置中心* 依赖alibaba-nacos-config* bootstrap.yml . 端口,application.name app-notice服务名,cloud.nacos.config配置中心(namespace,group,file-extension)* 其他配置放在nacos配置中心里,>6. sentinel限流
java -Dserver.port=8180 -Dcsp.sentinel.dashboard.server=localhost:8180-Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar* sentinel服务与notice进行连接. 在notice配置中添加spring.cloud.sentinel.(transport/eager). 启动sentinel服务 notice服务 就可在sentinel控制台看到服务app-notice# 2021-04-16 ----------------------------
> ms-mail
> ms-sms
> 优惠券子系统
> 权益系统
> 积分系统
> segmentfault> 微服务网关,spring cloud gateway* 认证做网关统一处理,多个服务就不用重复登录> gateway 服务转发/重定向 * 依赖: spring-cloud-starter-gateway* 配置: spring.cloud.gateway.routes 路由 --通过路由找到指定的资源> provider 8081,8082 两个服务 -- gateway+ribbon 负载均衡 * 要在nacos中注册gateway服务 注册发现> url请求 进行filter(过滤) --是个handler. handler --处理器
. interceptor --拦截器
. aspect --切面
. AOP --面向切面编程> 网关限流* 依赖 sentinel* https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel * gateway添加配置* sentinel版本不同,配置不同* 网关配置sentinel: 依赖,yml配置,vm参数-Dcsp.sentinel.app.type=1* 限流 Blocked by Sentinel: ParamFlowException> json三剑客* jackson稳 fastjson快不稳 gson近几年 # 2021-04-19 ----------------------------
> 网关* 1.保证服务的安全 2.统一服务入口管理 3.负载均衡 4.限流 5.鉴权* Spring Cloud Gateway 依赖,配置* Gateway底层 Natty-框架* 负载均衡 --基于服务名找到具体的服务实例, . 在nacos服务中心注册找到服务名 通过ribbon找到具体的服务实例. Ribbon(Netfilx)* 网关层面服务映射 . 断言/谓词-path 服务名/服务实例* 限流. route id. api. 算法: > Predicate 断言 谓词* 用于定义路由转发的条件 条件判断,断言为真执行路由> ZipKin 分布式实时数据追踪系统* https://github.com/openzipkin/zipkin* 依赖* 扫描了sleuth的日志> njx
> FastDFS
> ElasticSearch
> Redis
> MySQL# 2021-04-20 ----------------------------
> 网关 --依赖* 和spring-mvc有冲突 把父工程中的web依赖放在要使用的子工程中* 父工程中有mysql依赖,要在网关中设置 数据库url. 解决: 把父工程中的web,mysql依赖放在modules中> 微服务相关的依赖 > BIOS* 硬件配置* 基本输入输出系统 >* 分布式架构
> 分布式环境> centos* 克隆. 完整克隆. 链接克隆* 快照 --某个时间点上完整系统的镜像, 通过快照文件恢复系统之前的文件. 没做异步动作做一个快照, 错误之后方便返回重做* Linux系统操作软件. MobaXtem linux系统远程操作. WinSCP SSH 的开源图形化 SFTP 客户端 在本地与远程计算机间安全地复制文件,并且可以直接编辑文件。. docker 容器平台 容器化技术 --阿里镜像. 镜像* 文件目录. libs /sca /jdk # 2021-04-21 ----------------------------
>> -----------* Vmware* CentOS* 克隆,快照* MobaXTerm --远程控制linux /WinSCP --与linux传输文件* Docker 容器平台 --安装程序 方便启动* JDK -运行zipkin.jar程序文件* Database 数据库* redis 内存数据库* Ngnix 分布式中间件* RedisDesktopManager --操作nginx的软件> docker* 容器技术 -虚拟操作系统,虚拟硬件,可开多个docker* 所有的应用程序跑在docker平台下
> 安装jdk. docker stop . docker ps 查看运行的镜像. docker run -d -p 9411:9411 -v(挂载) /root/libs/sca:/sca --entrypoint java benwang6/tedu-jdk -jar /sca/zipkin-server-2.23.2-exec.jar. docker run -d -p 9411:9411 -v /root/libs/sca:/sca --entrypoint java benwang6/tedu-jdk -jar /sca/zipkin-server-2.23.2-exec.jar 运行jar文件镜像. 宿主机 使用ip连接到的linux电脑. docker exec -it id(docker镜像) bash 切换宿主机到docker镜像. ls. exit 切换为宿主机. docker rmi 147051a21fd9 删除镜像. usr . vim Dockerfile 编辑文件. esc :wq 编辑文件退出保存> mysql. docker start mysql 运行mysql镜像. docker exec -it mysql bash. exit* mysql创建用户 create user user01@'localhost' identified by 'password'; GRANT privileges ON databasename.tablename TO 'username'@'host';.. % --远程用户 localhost --本地用户 . create user 'lv'@'%' identified by 'lv';. grant all on *.* to 'lv'@'%';* 连接数据库 命令行 mysql -ulv -h192.168.140.131 -plv > 内存数据库/KV数据库 redis* docker start redis 运行redis镜像* docker exec -it redis redis-cli 进入redis> linux unix最早* 去IOE IBM,Oracle,EMC.? 应用场景.? 体系结构.? 文件结构命令.> 初学者使用* 文件系统. 所有的资源都是目录在 /root 根目录下* 指令. su 切换用户. pwd 查看所在目录. exit. 重启 reboot / shutdown -r now/10. 关机 half / shutdown -h now/10. cd. cd / . cd ~ cd /root cd. cd . 当前. cd .. 上一级 cd usr/local/docker cd ../../... cd - 上一级(从哪里进入到这个目录的上一级)且 显示目录. ls. ls 目录显示. ls -l ll. ls *.txt. mkdir. mkdir test. mkdir -p t1/t2/t3. mkdir -m 777 c 权限为777的目录 7.rwx 6.rw- 5.r-x 读写执行 (二进制的 7 111). rmdir test 删除目录(空目录). touch. touch c1.txt 创建文件 . touch -a c3.txt 改最后访问时间 . stat c3.txt 显示最后修改时间. rm . rm c3.txt . rm -f c3.txt. rm -rf c3 递归删除目录下所有文件. rm -rf * 删除所有文件. rm -rf /* 删除所有子目录所有文件. 文件内容操作. cat 输出文件所有内容. more/less 分页输出. tail -10 l1.txt 输出文件最后10行. tail -f l1.txt 动态查看日志. ctrl+c 结束查看esc :wq 编辑完文件,退出保存# 2021-04-22 ----------------------------
> docker运行sentinel* docker run -d(本地) -p(端口) 8180(本地端口):8080(镜像端口) -v(挂载点) /root/libs/sca:sca jdk:8 java -jar /sca/sentinel-dashboard-1.8.0.jar* benwang6/tedu-jdk 老师的jdk. docker run -d -p 8180:8080 -v /root/libs/sca/:/sca --entrypoint java benwang6/tedu-jdk -jar /sca/sentinel-dashboard-1.8.0.jar. docker run -d -p 9411:9411 -v /root/libs/sca/:/sca --entrypoint java benwang6/tedu-jdk -jar /sca/zipkin-server-2.23.2-exec.jar* jdk:8 自己建的jdk. docker run -d -p 8180:8080 -v /root/libs/sca/:/sca jdk:8 java -jar /sca/sentinel-dashboard-1.8.0.jar. docker run -d -p 9411:9411 -v /root/libs/sca/:/sca jdk:8 java -jar /sca/zipkin-server-2.23.2-exec.jar> jdk镜像* 创建文件 放linux-jdk.tar.gz * 在此目录下 创建文件Dockerfile 编辑文件* 在此目录下 构造镜像 docker build -t jdk:8 . ( . 表示当前目录 )* 测试镜像 启动zipkin服务# 2021-04-23 ----------------------------
> redis* 应用: 验证码 热门浏览 * hashmap* nosql 非关系型数据库 * 内存数据库* KV存储系统, 分布式缓存数据库 . 断电丢失数据
* 杀进程 ps -ef | grep redis kill -9 serverid. set lv 23. get lv. save* 配置redis 周期性写入磁盘* 特性. 分布性 支持主从* 配置redis /usr/local/docker/redis/conf/redis.config. * 退出. shutdown 会执行save之后退出 . exit 也会执行save操作. 正常终止 会执行save操作 持久化. 断电异常终止 数据会丢失> LRU catch> 测试 改redis.conf* bind ip注释掉* protected-mode 保护模式 no# 2021-04-25 ----------------------------
> redis* 经常访问的(访问量大) 的数据在存储时 存在数据库一份,redis中一份 * 计数 strlen* 追加 append* 分布式自增id incr 雪花算法* 分布式锁 * 点赞操作 incr decr# 2021-04-26 ----------------------------
> Nginx> 正向代理* 代理客户端 --访问谷歌 通过一个代理> 反向代理* 代理服务器 --外卖平台代理餐厅> 性能高 稳定client ---> [ Nginx ---> Tomcat ] 客户端请求 发送给nginx nginx再给tomcatwindows java -jar tomcat10001.jar
linux docker run -d -p 10001:10001 -v /root/libs/app:/app jdk:8 java -jar /app/tomcat10001.jardocker run 创建一个容器
docker start 运行服务service nginx reloadcp 原文件名 新名 复制文件
mv 原文件名 新名 重命名docker stop $(docker ps -a -q) 停止所有的container
docker rmi -f imageid 强制删除某个容器 (必须把所有container停止)sudo service docker restart 重启docker服务
docker exec -it nginx service nginx reload 重新加载nginx配置文件( 不用进入容器 )> docker命令启动jar包* docker run -d -p 5614:5614 -v /root/libs/app:/app jdk:8 java -jar /app/tomcatapp-1.0.jar. -d 本地运行. -p 外部端口(访问端口) : jar包中配置文件端口 . -v jar包所在路径 : 容器路径(docker run创建的容器) . jdk:8 jdk的镜像 名字. java -jar ... 运行jar文件# 2021-04-27 ----------------------------
> nacos* linux执行.sql文件 . 1.要在容器中运行.sql文件. 2.把 XX.sql 文件放在mysql的容器所对应的本地目录. 3.mysql容器sudo docker run -p 3306:3306 --name mysql \-v /usr/local/docker/mysql/mysql-files:/var/lib/mysql-files \-v /usr/local/docker/mysql/conf:/etc/mysql \-v /usr/local/docker/mysql/logs:/var/log/mysql \-v /usr/local/docker/mysql/data:/var/lib/mysql \-e MYSQL_ROOT_PASSWORD=root \-d mysql:8.0.23
> 打包项目* 依赖: 添加. <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.3.2.RELEASE</version><configuration><mainClass>com.cy.MsGatewayApplication</mainClass></configuration><executions><execution><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build>* 端口: localhost 改成 linux-ipjava -Dserver.port=8180 -Dcsp.sentinel.dashboard.server=localhost:8180 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar
startup.cmd -m standalone# 2021-04-28 ----------------------------
> gateway 网关项中 继承的项目中 依赖不能有mysql,jdbc依赖docker run -d -p 8180:8080 --name sentinel -v /root/libs/sca:/sca jdk:8 java -jar /sca/sentinel-dashboard-1.8.0.jardocker run -d -p 9411:9411 --name zipkin -v /root/libs/sca:/sca jdk:8 java -jar /sca/zipkin-server-2.23.2-exec.jardocker run -d -p 9000:9000 --name gateway -v /root/libs/app:/app jdk:8 java -Dcsp.sentinel.app.type=1 -jar /app/ms-gateway.jardocker run -d -p 9001:9001 --name log -v /root/libs/app:/app jdk:8 java -jar /app/ms-log.jardocker run -d -p 9002:9002 --name notice -v /root/libs/app:/app jdk:8 java -jar /app/ms-naccos.jar> MSA 部署在linux* linux环境需求. mysql. jdk. nginx. nacos. sentinel. zipkin* 服务打包 package. 依赖. bootstrap.yml 中 ip. ms-gateway ms-log 单独打包 maven package操作 . ms-notice 整个项目打包03-sca (ms-notice依赖于ms-log-commony依赖于ms-log-api) * 打包的.jar文件拷贝到linux本地目录中. docker 运行jar文件. 访问 http://192.168.140.131:9000/notice/* 配置nginx default.conf文件. 访问 http://192.168.140.131/notice/