Mr.zhang's Blog

学习笔记,技术博客


  • 首页

  • 归档

  • 分类

  • 标签

  • 关于

  • 搜索

满月记录

发表于 2020-03-01 | 分类于 Anniversary
1
闹闹照片

 image-20200321194317130

# Anniversary
AWS总结

AWS总结

发表于 2019-07-17 | 分类于 technology

EC2

EC2实例类型选择考虑因素

  • 核心数量
  • 内存大小
  • 存储大小和类型
  • 网络性能
  • CPU技术

实例

实例系列 部分使用案例
通用型(T2、T3、M5、M4) 低流量网站和Web应用程序
中小型数据库
计算优化型(C5、C4) 高性能Web服务器
视频编码
内存优化型(X1e、X1、R4) 高性能数据库
份额不是内存缓存
存储优化型(H1、I3、D2) 数据仓库
日志或数据处理应用程序
加速计算型(P3、P2、G3、F1) 3D可视化
机器学习

S3

​ 面向Internet的存储服务,原生在线、Http访问,随时从Web的任何位置存储和检索任意数量的数据。高度可扩展、可靠、快速且持久。

使用场景

  • 一次写多次读的场景
  • 存储和备份

访问控制

  • 默认访问(只能自己访问)
  • 公有访问(自己以及其他人可以访问)

特点

  • S3将数据以对象的形式存储在存储桶中

  • 设计为99.999999999%的持久性

  • 可以控制对存储桶及其对象的访问

  • 对象由文件和元数组组成

  • 每个账户最多可以包含100个存储桶 (桶是为了管理)

  • 存储桶内对象个数没有限制

  • 可启用静态加密和动态加密 (信封加密 )

  • 对象可以提供URL访问

    http://johnsmith.s3.amazonaws.com/photos/puppy.jpg

    johnsmith —存储桶 puppy–对象主键

存储桶

  • 在最高级别组织Amazon S3命令空间
  • 识别负责存储和数据传输计费的账户
  • 在访问控制方面发挥作用
  • 用作使用率报告的汇总单位
  • 存储桶名称是全球唯一的

S3存储类

存储类 持久性 可用性 其他注意事项
Amazon S3标准 99.999999999% 99.99% 存贵,取便宜
Amazon S3标准-不频繁访问(IA) 99.999999999% 99.9% 对象具有检索费用
最适合不频繁访问的数据
存便宜,取贵
Glacier 99.999999999% 99.99%(还原后) 无法进行实时访问
必须先还原对象,然后才能访问对象
还原对象需要花费1分钟到12小时

弹性(高可用)和恢复能力

Auto Scaling

  • 场景
    • 自动扩展EC2容量,非常适用使用率不断变化的应用程序
  • 三重服务

  • Auto Scaling组

    Auto Scaling组中的实例被视为一个逻辑组以便进行实例扩展和管理

  • Auto Scaling基本生命周期

ELB(Elastic Load Balance)

  • 功能

    • 在多个实例间分配流量
    • 支持运行状况检查,可检测出运行不正常的Amazon EC2实例
    • 支持Amazon EC2实例的HTTP、HTTPS和TCP流量的路由和负载均衡
  • 工作原理

CloudWatch

  • 功能

    • 适用于AWS云资源和AWS上运行的应用程序的监控服务,提供图形化的统计数据,设置报警
    • 了解资源利用率、运行性能和整体需求模式
    • 自定义自己的应用程序特定指标
    • 可通过AWS管理控制台、API、软件开发工具包或CLI访问
  • 架构

# DevOps
IDEA激活
满月记录

IDEA激活

发表于 2019-07-01 | 分类于 technology

IDEA激活

1.补丁网盘自取

链接: https://pan.baidu.com/s/16rQPgO0ypNAvAamxYtS5ww 提取码: k25q

2.配置

  • 补丁copy至idea安装目录的bin目录下
  • bin目录中找到idea.exe.vmoptions和idea64.exe.vmoptions两个文件,在文件最后追加一行内容:-javaagent:idea安装路径\bin\JetbrainsCrack-release-enc.jar

3.激活

  • 打开IDEA,选择激活码激活,激活码如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    ThisCrackLicenseId-{
    “licenseId”:”11011”,
    “licenseeName”:”Wechat”,
    “assigneeName”:”tree-deep-see-deer”,
    “assigneeEmail”:”2378437815@qq.com”,
    “licenseRestriction”:””,
    “checkConcurrentUse”:false,
    “products”:[
    {“code”:”II”,”paidUpTo”:”2099-12-31”},
    {“code”:”DM”,”paidUpTo”:”2099-12-31”},
    {“code”:”AC”,”paidUpTo”:”2099-12-31”},
    {“code”:”RS0”,”paidUpTo”:”2099-12-31”},
    {“code”:”WS”,”paidUpTo”:”2099-12-31”},
    {“code”:”DPN”,”paidUpTo”:”2099-12-31”},
    {“code”:”RC”,”paidUpTo”:”2099-12-31”},
    {“code”:”PS”,”paidUpTo”:”2099-12-31”},
    {“code”:”DC”,”paidUpTo”:”2099-12-31”},
    {“code”:”RM”,”paidUpTo”:”2099-12-31”},
    {“code”:”CL”,”paidUpTo”:”2099-12-31”},
    {“code”:”PC”,”paidUpTo”:”2099-12-31”}
    ],
    “hash”:”2911276/0”,
    “gracePeriodDays”:7,
    “autoProlongated”:false}
# DevOps
SpringBoot整合Swagger2
AWS总结

SpringBoot整合Swagger2

发表于 2019-04-17 | 分类于 technology

​ 如何构建一份合理高效的接口文档很重要,Swagger的出现可以完美解决了传统接口管理方式存在的痛点。以下介绍Spring Boot整合Swagger2的流程,连带填坑。

SpringBoot整合Swagger2

  • 引入相应的maven包

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.7.0</version>
    </dependency>

    <dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.7.0</version>
    </dependency>
  • 编写Swagger2的配置类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    package com.swagger.demo.config;

    import io.swagger.annotations.Api;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import springfox.documentation.builders.ApiInfoBuilder;
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.builders.RequestHandlerSelectors;
    import springfox.documentation.service.ApiInfo;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spring.web.plugins.Docket;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;

    /**
    * @author Mr.zhang
    * @description swagger配置类
    * @date 9:06 AM 2019/4/17
    */
    @Configuration
    @EnableSwagger2
    public class Swagger2Config {
    @Value("${swagger2.enable}")
    private boolean enable;

    @Bean
    public Docket createRestApi() {
    return new Docket(DocumentationType.SWAGGER_2)
    .groupName("Demo模块")
    .select()
    .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
    .paths(PathSelectors.regex("/demo.*"))
    .build()
    .apiInfo(apiInfo())
    .enable(enable);
    }

    private ApiInfo apiInfo() {
    return new ApiInfoBuilder()
    .title("Demo模块接口文档")
    .description("提供Demo模块文档")
    .termsOfServiceUrl("https://xingtian.github.io/trace.github.io/")
    .version("1.0")
    .build();
    }
    }

    ​ 注解@EnableSwagger2开启swagger2,apiInfo是接口文档的基本说明信息,包括标题、描述、服务网址、联系人、版本等信息。

    ​ Docket创建,通过groupName进行分组,paths属性进行过滤,apis属性可以设置扫描包,或者通过注解的方式标识。

    ​ enable属性主要用于控制是否生成接口文档,比如:生产环境不生成接口文档。

  • Controller层类和方法添加相关注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    package com.swagger.demo.web;

    import com.swagger.demo.entity.ResultModel;
    import com.swagger.demo.entity.User;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiImplicitParam;
    import io.swagger.annotations.ApiImplicitParams;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.web.bind.annotation.*;

    import java.util.ArrayList;
    import java.util.List;

    /**
    * @author Mr.zhang
    * @description Demo控制层
    * @date 9:57 AM 2019/4/17
    */
    @RestController
    @RequestMapping("/demo")
    @Api(tags = "demo模块")
    public class DemoController {


    @GetMapping("/query/{id}")
    @ApiOperation("通过ID查询")
    @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "int", paramType = "path")
    public ResultModel<User> findById(@PathVariable int id) {
    return ResultModel.success("id查询成功", new User());
    }


    @GetMapping("/query/ids")
    @ApiOperation("通过ID列表查询")
    public ResultModel<List<User>> findByIdIn(int[] ids) {
    return ResultModel.success("in查询成功", new ArrayList<>());
    }


    @GetMapping("/query/user")
    @ApiOperation("通过用户实体查询")
    public ResultModel<List<User>> findByUser(User user) {
    return ResultModel.success("通过实体查询成功", new ArrayList<>());
    }


    @GetMapping("/query/all")
    @ApiOperation("查询所有用户")
    public ResultModel<List<User>> findAll() {
    return ResultModel.success("全体查找成功", new ArrayList<>());
    }


    @GetMapping("/query/username")
    @ApiOperation("通过用户名称模糊查询")
    @ApiImplicitParam(name = "userName", value = "用户名称")
    public ResultModel<List<User>> findByUserName(String userName) {
    return ResultModel.success(new ArrayList<>());
    }


    @PostMapping("/insert")
    @ApiOperation("新增默认用户")
    public ResultModel<Integer> insert() {
    User user = new User();
    user.setUserName("zhongshiwen");
    user.setNickName("zsw");
    user.setRealName("钟仕文");
    user.setPassword("zsw123456");
    user.setGender("男");
    return ResultModel.success("新增用户成功", user.getId());
    }


    @PutMapping("/update")
    @ApiOperation("更新用户信息")
    public ResultModel<Integer> update(User user) {
    return ResultModel.success(user.getId());
    }


    @PutMapping("/update/status")
    @ApiOperation("更新单个用户状态")
    @ApiImplicitParams({
    @ApiImplicitParam(name = "id", value = "用户ID", required = true),
    @ApiImplicitParam(name = "status", value = "状态", required = true)
    })
    public ResultModel<User> updateStatus(int id, byte status) {
    return ResultModel.success(new User());
    }


    @DeleteMapping("/delete")
    @ApiOperation("删除单个用户")
    @ApiImplicitParam(value = "用户ID", required = true)
    public ResultModel<Integer> delete(int id) {
    return ResultModel.success(id);
    }
    }
  • 返回对象ResultModel

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    package com.swagger.demo.entity;

    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;

    /**
    * @author Mr.zhang
    * @description 返回对象
    * @date 10:00 AM 2019/4/17
    */
    @ApiModel(description = "返回结果")
    @Data
    public final class ResultModel<T> {
    @ApiModelProperty("是否成功: true or false")
    private boolean result;
    @ApiModelProperty("描述性原因")
    private String message;
    @ApiModelProperty("业务数据")
    private T data;

    private ResultModel(boolean result, String message, T data) {
    this.result = result;
    this.message = message;
    this.data = data;
    }

    public static<T> ResultModel<T> success(T data) {
    return new ResultModel<>(true, "SUCCESS", data);
    }


    public static<T> ResultModel<T> success(String message, T data) {
    return new ResultModel<>(true, message, data);
    }


    public static ResultModel failure() {
    return new ResultModel<>(false, "FAILURE", null);
    }


    public static ResultModel failure(String message) {
    return new ResultModel<>(false, message, null);
    }
    }
  • ApiModel属性对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    package com.swagger.demo.entity;

    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    import java.time.LocalDate;
    import java.time.LocalDateTime;

    /**
    * @author Mr.zhang
    * @description 用户表实体
    * @date 10:03 AM 2019/4/17
    */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @ApiModel
    public class User {
    @ApiModelProperty("用户ID") private Integer id;
    @ApiModelProperty("账户名") private String userName;
    @ApiModelProperty("用户昵称") private String nickName;
    @ApiModelProperty("真实姓名") private String realName;
    @ApiModelProperty("身份证号码") private String identityCard;
    @ApiModelProperty("性别") private String gender;
    @ApiModelProperty("出生日期") private LocalDate birth;
    @ApiModelProperty("手机号码") private String phone;
    @ApiModelProperty("邮箱") private String email;
    @ApiModelProperty("密码") private String password;
    @ApiModelProperty("用户头像地址") private String logo;
    @ApiModelProperty("账户状态 0:正常; 1:冻结; 2:注销") private Byte status;
    @ApiModelProperty("个性签名") private String summary;
    @ApiModelProperty("用户所在区域码") private String areaCode;
    @ApiModelProperty("注册时间") private LocalDateTime registerTime;
    @ApiModelProperty("最近登录时间") private LocalDateTime lastLoginTime;
    }

    Swagger2几个重要注解

    @Api:用在请求的类上,表示对类的说明

    • tags “说明该类的作用,可以在UI界面上看到的注解”

    • value “该参数没什么意义,在UI界面上也看到,所以不需要配置”

    @ApiOperation:用在请求的方法上,说明方法的用途、作用

    • value=”说明方法的用途、作用”
    • notes=”方法的备注说明”

    @ApiImplicitParams:用在请求的方法上,表示一组参数说明 @ApiImplicitParam:用在@ApiImplicitParams注解中,指定一个请求参数的各个方面

    • value:参数的汉字说明、解释

    • required:参数是否必须传

    • paramType: 参数放在哪个地方

      • 1.header –> 请求参数的获取:@RequestHeader
      • 2.query –> 请求参数的获取:@RequestParam
      • 3.path(用于restful接口)–> 请求参数的获取:@PathVariable
      • 4.body(不常用)
      • 5.form(不常用)
    • dataType:参数类型,默认String,其它值dataType=”Integer”

    • defaultValue:参数的默认值

    @ApiResponses:用在请求的方法上,表示一组响应 @ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息

    • code:数字,例如400
    • message:信息,例如”请求参数没填好”
    • response:抛出异常的类

    @ApiModel:主要有两种用途:

    • 用于响应类上,表示一个返回响应数据的信息

    • 入参实体:使用@RequestBody这样的场景, 请求参数无法使用@ApiImplicitParam注解进行描述的时候

    @ApiModelProperty:用在属性上,描述响应类的属性 最终呈现结果

  • 启动应用后,会自动生成页面

    地址:http://{root-path}/swagger-ui.html(http://localhost:8080/swagger-ui.html)

    效果如下:

    利用该文档可以在线测试接口

# Java
Docker 私服
IDEA激活

Docker 私服

发表于 2019-04-15 | 分类于 technology

Harbor搭建Docker 私服

https://blog.51cto.com/11093860/2117805

1.安装docker-compose

1
sudo pip install docker-compose

2.下载Harbor包

https://github.com/vmware/harbor/releases

安装有两种方式,一种是off-line ,一种是on-line,即离线和在线安装,离线安装需要下载的安装包较大,在线安装下载的安装包很小,课题根据自己的情况选择

3.解压,进入安装包

1
2
tar -zxvf harbor*.tgz
cd harbor

4.修改配置文件

1
vim docker-compose.yml

1
vim harbor.cfg

5.执行./prepare,更新一下配置文件

1
sudo  ./prepare

6.执行./install.sh,开始安装并启动

1
sudo ./install.sh

7.在火狐浏览器中访问测试,此处的用户名默认为admin,密码在habor.cfg中,可以自己设

地址 IP/harbor/sign-in/

# DevOps
Redis实现分布式锁
SpringBoot整合Swagger2

Redis实现分布式锁

发表于 2019-03-28 | 分类于 technology

分布式锁的实现方案

Spring早就提供了分布式锁的实现,早期,分布式锁的相关代码存在与Spring Cloud的子项目Spring Cloud Cluster中,后来被迁移到了Spring Integration中。

​ Spring Cloud Cluster的GitHub:https://github.com/spring-cloud/spring-cloud-cluster/

​ Spring Integration的GitHub:https://github.com/spring-projects/spring-integration/

官方对于Spring Integration的说法是 这是一个企业集成模式的实现。Spring Cloud Stream的底层也是Spring Integration。

Spring Integration提供了多种全局锁,现在我们在这里只介绍基于Redis的分布式锁

基于Spring Integration 实现Redis的分布式锁

1.依赖

1
2
3
4
5
6
7
8
9
10
11
12
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.Redis配置

1
2
3
4
spring:
redis:
port: 6379
host: localhost

3.RedisLock初始化

1
2
3
4
5
6
7
@Configuration
public class RedisLockConfiguration {
@Bean
public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) {
return new RedisLockRegistry(redisConnectionFactory, "RedisLockRegistry");
}
}

​ org.springframework.integration.redis.util.RedisLockRegistry的注释详细描述了该类的特性以及使用方式。

4.测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* @author Mr.zhang
* @description
* @date 1:43 PM 2019/3/26
*/
@Slf4j
@RestController
@RequestMapping("redisLock")
public class RedisLockController {

@Autowired
private RedisLockRegistry redisLockRegistry;

@GetMapping("test")
public void test() throws InterruptedException {
Lock lock = redisLockRegistry.obtain("redisLock");
boolean b1 = lock.tryLock(3, TimeUnit.SECONDS);
log.info("b1 is : {}", b1);

TimeUnit.SECONDS.sleep(5);

boolean b2 = lock.tryLock(3, TimeUnit.SECONDS);
log.info("b2 is : {}", b2);

lock.unlock();
lock.unlock();
}
}
  • 启动1个实例,访问 http://localhost:8080/redisLock/test ,会看到类似如下的日志
1
2
2019-03-26 14:42:28.206  INFO 4913 --- [nio-8080-exec-1] c.r.lock.controller.RedisLockController  : b1 is : true
2019-03-26 14:42:33.212 INFO 4913 --- [nio-8080-exec-1] c.r.lock.controller.RedisLockController : b2 is : true
  • 启动2个实例,并迅速访问两个实例的 /test 端点,会在第二个实例上看到类似如下日志
1
2
3
4
5
6
7
8
[nio-8081-exec-1] c.r.lock.controller.RedisLockController  : b1 is : false
[nio-8081-exec-1] c.r.lock.controller.RedisLockController : b2 is : true
[nio-8081-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() ...

java.lang.IllegalStateException: You do not own lock at RedisLockRegistry:redisLock
at org.springframework.integration.redis.util.RedisLockRegistry$RedisLock.unlock(RedisLockRegistry.java:300) ~[spring-integration-redis-5.1.3.RELEASE.jar!/:5.1.3.RELEASE]
at com.redis.lock.controller.RedisLockController.test(RedisLockController.java:38) ~[classes!/:0.0.1-SNAPSHOT]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_144]

​ 说明第二个实例没有拿到锁,证明了分布式锁的存在

参考地址

# Java
SpringBoot整合RabbitMQ
Docker 私服

SpringBoot整合RabbitMQ

发表于 2019-03-27 | 分类于 technology

RabbitMQ支持持久化(MQ down或者MQ所在的服务器down了,消息不会丢失的机制)

整合步骤

添加依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

配置

1
2
3
4
5
6
spring:
rabbitmq:
host: 10.0.96.102 # MQ部署IP
port: 5672 # MQ应用端口 不是web端口
username: admin
password: admin
# Java
RabbitMQ 安装
Redis实现分布式锁

RabbitMQ 安装

发表于 2019-03-27 | 分类于 technology

安装

​ 由于RabbitMQ是基于Erlang语言开发,所以在安装RabbitMQ之前,需要先安装Erlang,RabbitMQ官网已经为我们提供了Erlang的安装包

  • Erlang下载地址:http://www.rabbitmq.com/releases/erlang/

    下载的Erlang安装包为: erlang-19.0.4-1.el7.centos.x86_64.rpm

  • RabbitMQ下载地址:https://www.rabbitmq.com/download.html

    下载的RabbitMQ安装包为:rabbitmq-server-3.6.8-1.el7.noarch.rpm

1.安装Erlang

1
yum install erlang-19.0.4-1.el7.centos.x86_64.rpm

​ 测试Erlang是否安装成功

1
erl -version

​ 出现以下信息则表示安装成功

1
Erlang (SMP,ASYNC_THREADS,HIPE) (BEAM) emulator version 8.0.3

2.安装RabbitMQ

1
yum install rabbitmq-server-3.6.8-1.el7.noarch.rpm

​ 运行RabbitMQ

1
service rabbitmq-server start

​ 停止RabbitMQ

1
service rabbitmq-server stop

用户配置

  • 添加用户

    1
    rabbitmqctl add_user admin admin
  • 添加管理员权限

    1
    rabbitmqctl set_user_tags admin administrator
  • 修改密码

    1
    rabbitmqctl add_user admin youpassword
  • 设置权限

    1
    rabbitmqctl  set_permissions  -p  '/'  admin '.' '.' '.'
  • 查看服务状态

    1
    service rabbitmq-server status

启用WEB管理

  • 启动web插件

    1
    rabbitmq-plugins enable rabbitmq_management

    访问地址http://IP:15672/

  • 删除guest用户

    1
    rabbitmqctl delete_user guest

    由于guest用户被限制,只能通过localhost访问,因此我们需要新建一个用户,并授予管理员权限

  • 添加Web访问权限
    注意:rabbitmq从3.3.0开始禁止使用guest/guest权限通过除localhost外的访问。如果想使用guest/guest通过远程机器访问,需要在rabbitmq配置文件中(/etc/rabbitmq/rabbitmq.config)中设置loopback_users为[],配置文件不存在创建即可。

    添加配置

    1
    [{rabbit, [{loopback_users, ["admin"]}]}]
# Java
RocketMQ
SpringBoot整合RabbitMQ

RocketMQ

发表于 2019-03-26 | 分类于 technology

rocketmq java 客户端调用No route info of this topic错误(原因版本不一致)

https://blog.csdn.net/whhwkm/article/details/81783322

# Java
RabbitMQ 详解
RabbitMQ 安装

RabbitMQ 详解

发表于 2019-03-26 | 分类于 technology

分布式消息中间件场景介绍

​ 背景

​ 使用过分布式中间件的人都知道,程序员使用起来并不复杂,常用的客户端 API 就那么几个,比我们日常编写程序时用到的 API 要少得多。但是分布式中间件在中小研发团队中使用得并不多,为什么会这样呢?

​ 原因是中间件的职责相对单一,客户端的使用虽然简单,但整个环境搭起来却不容易。

​ 场景介绍

​ 1、业务系统往往要求响应能力特别强,能够起到削峰填谷的作用

​ 2、解耦:如果一个系统挂了,则不会影响另外个系统的继续运行

​ 3、业务系统往往有对消息的高可靠要求,以及有对复杂功能如 Ack 的要求

​ 4、增强业务系统的异步处理能力,减少甚至几乎不可能出现并发现象

使用消息队列,就好比为了防汛而建葛洲坝,有大量数据的堆积能力,然后可靠地进行异步输出

​ RabbitMQ介绍

​ RabbitMQ 是基于 AMQP 实现的一个开源消息组件,主要用于在分布式系统中存储转发消息,由因高性能、高可用以及高扩展而出名的 Erlang 语言写成

​ 其中,AMQP(Advanced Message Queuing Protocol,即高级消息队列协议),是一个异步消息传递所使用的应用层协议规范,为面向消息的中间件设计

​ RabbitMQ 特点

​ 高可靠:RabbitMQ 提供了多种多样的特性让你在可靠性和性能之间做出权衡,包括持久化、发送应答、发布确认以及高可用性。

​ 高可用队列:支持跨机器集群,支持队列安全镜像备份,消息的生产者与消费者不论哪一方出现问题,均不会影响消息的正常发出与接收。

​ 灵活的路由:所有的消息都会通过路由器转发到各个消息队列中,RabbitMQ 内建了几个常用的路由器,并且可以通过路由器的组合以及自定义路由器插件来完成复杂的路由功能。

​ 支持多客户端:对主流开发语言(如:Python、Ruby、.NET、Java、C、PHP、ActionScript 等)都有客户端实现。

​ 集群:本地网络内的多个 Server 可以聚合在一起,共同组成一个逻辑上的 broker。

​ 扩展性:支持负载均衡,动态增减服务器简单方便。

​ 权限管理:灵活的用户角色权限管理,Virtual Host 是权限控制的最小粒度。

​ 插件系统:支持各种丰富的插件扩展,同时也支持自定义插件,其中最常用的插件是 Web 管理工具 RabbitMQ_Management

RabbitMQ 5种用法介绍

​ RabbitMQ共有5种使用方式,即单对单、单对多、发布订阅模式、按路由规则发送接收、主题

​ 1、单对单:单发送,单接收

​ 适用于一个生产者,一个消费者的情况

​ 2、单对多:单发送,多接收

​ 适用于只有一个生产者,多个消费者,如分布式的任务派发

​ 3、发布订阅模式:单发送,多接收

​ 一个生产者发送消息,多个消费者获取消息(同样的消息),包括一个生产者,一个交换机,多个队列,多个消费者。

​ 思路解读

​ > 一个生产者,多个消费者

​ > 每一个消费者都有自己的一个队列

​ > 生产者没有直接发消息到队列中,而是发送到交换机

​ > 每个消费者的队列都绑定到交换机上

​ > 消息通过交换机到达每个消费者的队列

​ 注意:交换机没有存储消息功能,如果消息发送到没有绑定消费队列的交换机,消息则丢失

​ 4、按路由规则发送接收:

​ 生产者发送消息到交换机并指定一个路由key,消费者队列绑定到交换机时要制定路由key(key匹配就能接受消息,key不匹配就不能接受消息),例如:我们可以把路由key设置为insert ,那么消费者队列key指定包含insert才可以接收消息,消费者队列key定义为update或者delete就不能接收消息。很好的控制了更新,插入和删除的操作。

​ 5、主题:

​ Exchange Type 为 topic,发送消息时,需要指定交换机及Routing Key,消费者的消息队列绑定到该交换机并匹配到Routing Key实现消息的订阅,订阅后则可接收消息。只有消费者队列绑定到该交换机且指定的Routing Key符合匹配规则,才能收到消息。

​ 其中Routing Key可以设置成通配符,如:* 或 #(* 表示匹配Routing Key中的某个单词,# 表示任意的Routing Key的消息都能被收到)。如果Routing Key由多个单词组成,则单词之间用 . 来分隔。

​ 命名规范

​ 交换机名的命名建议

​ Ex{AppID}.{自定义 ExchangeName},队列名的命名建议:MQ{AppID}.{自定义 QueueName}

​

# Java
Redis主从部署
RocketMQ
123
Mr.zhang

Mr.zhang

那天遇见,便是缘分

23 日志
3 分类
7 标签
E-Mail
© 2020 Mr.zhang
Today is another Good Day
鲁ICP备19015290号-1