
前言 本篇文章引导你使用Jenkins部署[SpringBoot项目],同时使用Docker和Git实现简单的持续集成和持续部署。(项目地址:sso-merryyou) 流程图如下: push代码到Github触发WebHook。(因网络原因,本篇使用gitee)Jenkins从仓库拉去代码mavem构建项目代码静态分析单元测试build镜像push镜像到镜像仓库(本篇使用的镜像仓库为网易镜像仓库)更新服务Jenkins安装 下载jenkins 从https://jenkins.io/download/下载对应的jenkins 初始化密码 访问本地:http://localhost:8080输入密码 选择插件 进入用户自定义插件界面,选择第二个(因为我们本次构建使用的为Pipelines) 勾选与Pipelines相关的插件 等待插件安装完成 配置用户名和密码 全局配置 系统管理-》全局工具配置 配置Git,JDK和Maven 安全配置 系统管理-》全局安全配置 勾选Allow anonymous read access取消防止跨站点请求伪造 新建任务 新建任务-》流水线 构建脚本 勾选触发远程构建 (WebHooks触发地址),填写简单的Pipeline script #!groovy pipeline{ agent any stages { stage('test'){ steps { echo "hello world" } } } } 测试脚本 立即构建 控制台输出 gitee集成WebHooks 添加SSH公匙 配置WebHooks 使用natapp实现内网穿透 修改脚本 修改Pipeline script #!groovy pipeline{ agent any //定义仓库地址 environment { REPOSITORY="https://gitee.com/merryyou/sso-merryyou.git" } stages { stage('获取代码'){ steps { echo "start fetch code from git:${REPOSITORY}" //清空当前目录 deleteDir() //拉去代码 git "${REPOSITORY}" } } stage('代码静态检查'){ steps { //伪代码检查 echo "start code check" } } stage('编译+单元测试'){ steps { echo "start compile" //切换目录 dir('sso-client1') { //重新打包 bat 'mvn -Dmaven.test.skip=true -U clean install' } } } stage('构建镜像'){ steps { echo "start build image" dir('sso-client1') { //build镜像 bat 'docker build -t hub.c.163.com/longfeizheng/sso-client1:1.0 .' //登录163云仓库 bat 'docker login -u longfei_zheng@163.com -p password hub.c.163.com' //推送镜像到163仓库 bat 'docker push hub.c.163.com/longfeizheng/sso-client1:1.0' } } } stage('启动服务'){ steps { echo "start sso-merryyou" //重启服务 bat 'docker-compose up -d --build' } } } } Pipeline的几个基本概念: Stage: 阶段,一个Pipeline可以划分为若干个Stage,每个Stage代表一组操作。注意,Stage是一个逻辑分组的概念,可以跨多个Node。 Node: 节点,一个Node就是一个Jenkins节点,或者是Master,或者是Agent,是执行Step的具体运行期环境。 Step: 步骤,Step是最基本的操作单元,小到创建一个目录,大到构建一个Docker镜像,由各类Jenkins Plugin提供。 更多Pipeline语法参考:pipeline 语法详解 测试 docker-compose up -d 启动服务 访问http://sso-taobao:8083/client1登录 修改内容效果如下: 更多效果图 代码下载 github:https://github.com/longfeizheng/sso-merryyougitee:https://gitee.com/merryyou/sso-merryyou文章来源:https://my.oschina.net/merryyou/blog/1799317
一、SQL查询优化(重要) 1.1 获取有性能问题SQL的三种方式 通过用户反馈获取存在性能问题的SQL;通过慢查日志获取存在性能问题的SQL;实时获取存在性能问题的SQL; 1.1.2 慢查日志分析工具相关配置参数: slow_query_log # 启动停止记录慢查日志,慢查询日志默认是没有开启的可以在配置文件中开启(on) slow_query_log_file # 指定慢查日志的存储路径及文件,日志存储和数据从存储应该分开存储 long_query_time # 指定记录慢查询日志SQL执行时间的阀值默认值为10秒通常,对于一个繁忙的系统来说,改为0.001秒(1毫秒)比较合适 log_queries_not_using_indexes #是否记录未使用索引的SQL 常用工具:mysqldumpslow和pt-query-digest pt-query-digest --explain h=127.0.0.1,u=root,p=p@ssWord slow-mysql.log 1.1.3 实时获取有性能问题的SQL(推荐) SELECT id,user,host,DB,command,time,state,info FROM information_schema.processlist WHERE TIME>=60 查询当前服务器执行超过60s的SQL,可以通过脚本周期性的来执行这条SQL,就能查出有问题的SQL。 1.2 SQL的解析预处理及生成执行计划(重要)1.2.1 查询过程描述(重点!!!)通过上图可以清晰的了解到MySql查询执行的大致过程: 发送SQL语句。查询缓存,如果命中缓存直接返回结果。SQL解析,预处理,再由优化器生成对应的查询执行计划。执行查询,调用存储引擎API获取数据。返回结果。 1.2.2 查询缓存对性能的影响(建议关闭缓存)第一阶段:相关配置参数: query_cache_type # 设置查询缓存是否可用 query_cache_size # 设置查询缓存的内存大小 query_cache_limit # 设置查询缓存可用的存储最大值(加上sql_no_cache可以提高效率) query_cache_wlock_invalidate # 设置数据表被锁后是否返回缓存中的数据 query_cache_min_res_unit # 设置查询缓存分配的内存块的最小单 缓存查找是利用对大小写敏感的哈希查找来实现的,Hash查找只能进行全值查找(sql完全一致),如果缓存命中,检查用户权限,如果权限允许,直接返回,查询不被解析,也不会生成查询计划。在一个读写比较频繁的系统中,建议关闭缓存,因为缓存更新会加锁。将query_cache_type设置为off,query_cache_size设置为0。 1.2.3 第二阶段:MySQL依照执行计划和存储引擎进行交互 这个阶段包括了多个子过程: 一条查询可以有多种查询方式,查询优化器会对每一种查询方式的(存储引擎)统计信息进行比较,找到成本最低的查询方式,这也就是索引不能太多的原因。 1.3 会造成MySQL生成错误的执行计划的原因 1、统计信息不准确 2、成本估算与实际的执行计划成本不同  3、给出的最优执行计划与估计的不同4、MySQL不考虑并发查询 5、会基于固定规则生成执行计划 6、MySQL不考虑不受其控制的成本,如存储过程,用户自定义函数 1.4 MySQL优化器可优化的SQL类型查询优化器:对查询进行优化并查询mysql认为的成本最低的执行计划。 为了生成最优的执行计划,查询优化器会对一些查询进行改写 可以优化的sql类型 1、重新定义表的关联顺序; 2、将外连接转换为内连接; 3、使用等价变换规则; 4、优化count(),min(),max();  5、将一个表达式转换为常数; 6、子查询优化; 7、提前终止查询,如发现一个不成立条件(如where id = -1),立即返回一个空结果; 8、对in()条件进行优化; 1.5 查询处理各个阶段所需要的时间1.5.1 使用profile(目前已经不推荐使用了) set profiling = 1; #启动profile,这是一个session级的配制执行查询 show profiles; # 查询每一个查询所消耗的总时间的信息 show profiles for query N; # 查询的每个阶段所消耗的时间 1.5.2 performance_schema是5.5引入的一个性能分析引擎(5.5版本时期开销比较大)启动监控和历史记录表:use performance_schema update setup_instruments set enabled='YES',TIME = 'YES' WHERE NAME LIKE 'stage%'; update set_consumbers set enabled='YES',TIME = 'YES' WHERE NAME LIKE 'event%'; 1.6 特定SQL的查询优化1.6.1 大表的数据修改1.6.2 大表的结构修改利用主从复制,先对从服务器进入修改,然后主从切换(推荐) 添加一个新表(修改后的结构),老表数据导入新表,老表建立触发器,修改数据同步到新表, 老表加一个排它锁(重命名), 新表重命名, 删除老表。修改语句这个样子: alter table sbtest4 modify c varchar(150) not null default '' 利用工具修改:1.6.3 优化not in 和 <> 查询 子查询改写为关联查询: 二、分库分表2.1 分库分表的几种方式分担读负载 可通过 一主多从,升级硬件来解决。2.1.1 把一个实例中的多个数据库拆分到不同实例(集群) 拆分简单,不允许跨库。但并不能减少写负载。 2.1.2 把一个库中的表分离到不同的数据库中该方式只能在一定时间内减少写压力。 以上两种方式只能暂时解决读写性能问题。 2.1.3 数据库分片对一个库中的相关表进行水平拆分到不同实例的数据库中2.1.3.1 如何选择分区键 分区键要能尽可能避免跨分区查询的发生分区键要尽可能使各个分区中的数据平均 2.1.3.2 分片中如何生成全局唯一ID扩展:表的垂直拆分和水平拆分 文章来源:https://segmentfault.com/a/1190000013781544
本章内容文章内容搜索思路搜索内容分词搜索查询语句筛选条件分页、排序条件小结 一、文章内容搜索思路上一篇讲了在怎么在 Spring Boot 2.0 上整合 ES 5 ,这一篇聊聊具体实战。简单讲下如何实现文章、问答这些内容搜索的具体实现。实现思路很简单: 基于「短语匹配」并设置最小匹配权重值哪来的短语,利用 IK 分词器分词基于 Fiter 实现筛选基于 Pageable 实现分页排序这里直接调用搜索的话,容易搜出不尽人意的东西。因为内容搜索关注内容的连接性。所以这里处理方法比较 low ,希望多交流一起实现更好的搜索方法。就是通过分词得到很多短语,然后利用短语进行短语精准匹配。 ES 安装 IK 分词器插件很简单。第一步,在下载对应版本 https://github.com/medcl/elasticsearch-analysis-ik/releases。第二步,在 elasticsearch-5.5.3/plugins 目录下,新建一个文件夹 ik,把 elasticsearch-analysis-ik-5.5.3.zip 解压后的文件拷贝到 elasticsearch-5.1.1/plugins/ik 目录下。最后重启 ES 即可。 二、搜索内容分词 安装好 IK ,如何调用呢? 第一步,我这边搜搜内容会以 逗号 拼接传入。所以会先将逗号分割 第二步,在搜索词中加入自己本身,因为有些词经过 ik 分词后就没了... 这是个 bug 第三步,利用 AnalyzeRequestBuilder 对象获取 IK 分词后的返回值对象列表 第四步,优化分词结果,比如都为词,则保留全部;有词有字,则保留词;只有字,则保留字 核心实现代码如下: /** * 搜索内容分词 */ protected List<String> handlingSearchContent(String searchContent) { List<String> searchTermResultList = new ArrayList<>(); // 按逗号分割,获取搜索词列表 List<String> searchTermList = Arrays.asList(searchContent.split(SearchConstant.STRING_TOKEN_SPLIT)); // 如果搜索词大于 1 个字,则经过 IK 分词器获取分词结果列表 searchTermList.forEach(searchTerm -> { // 搜索词 TAG 本身加入搜索词列表,并解决 will 这种问题 searchTermResultList.add(searchTerm); // 获取搜索词 IK 分词列表 searchTermResultList.addAll(getIkAnalyzeSearchTerms(searchTerm)); }); return searchTermResultList; } /** * 调用 ES 获取 IK 分词后结果 */ protected List<String> getIkAnalyzeSearchTerms(String searchContent) { AnalyzeRequestBuilder ikRequest = new AnalyzeRequestBuilder(elasticsearchTemplate.getClient(), AnalyzeAction.INSTANCE, SearchConstant.INDEX_NAME, searchContent); ikRequest.setTokenizer(SearchConstant.TOKENIZER_IK_MAX); List<AnalyzeResponse.AnalyzeToken> ikTokenList = ikRequest.execute().actionGet().getTokens(); // 循环赋值 List<String> searchTermList = new ArrayList<>(); ikTokenList.forEach(ikToken -> { searchTermList.add(ikToken.getTerm()); }); return handlingIkResultTerms(searchTermList); } /** * 如果分词结果:洗发水(洗发、发水、洗、发、水) * - 均为词,保留 * - 词 + 字,只保留词 * - 均为字,保留字 */ private List<String> handlingIkResultTerms(List<String> searchTermList) { Boolean isPhrase = false; Boolean isWord = false; for (String term : searchTermList) { if (term.length() > SearchConstant.SEARCH_TERM_LENGTH) { isPhrase = true; } else { isWord = true; } } if (isWord & isPhrase) { List<String> phraseList = new ArrayList<>(); searchTermList.forEach(term -> { if (term.length() > SearchConstant.SEARCH_TERM_LENGTH) { phraseList.add(term); } }); return phraseList; } return searchTermList; } 三、搜索查询语句 构造内容枚举对象,罗列需要搜索的字段,ContentSearchTermEnum 代码如下: import lombok.AllArgsConstructor; @AllArgsConstructor public enum ContentSearchTermEnum { // 标题 TITLE("title"), // 内容 CONTENT("content"); /** * 搜索字段 */ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } 循环进行「短语搜索匹配」搜索字段,然后并设置最低权重值为 1。核心代码如下: /** * 构造查询条件 */ private void buildMatchQuery(BoolQueryBuilder queryBuilder, List<String> searchTermList) { for (String searchTerm : searchTermList) { for (ContentSearchTermEnum searchTermEnum : ContentSearchTermEnum.values()) { queryBuilder.should(QueryBuilders.matchPhraseQuery(searchTermEnum.getName(), searchTerm)); } } queryBuilder.minimumShouldMatch(SearchConstant.MINIMUM_SHOULD_MATCH); } 四、筛选条件搜到东西不止,有时候需求是这样的。需要在某个品类下搜索,比如电商需要在某个 品牌 下搜索商品。那么需要构造一些 fitler 进行筛选。对应 SQL 语句的 Where 下的 OR 和 AND 两种语句。在 ES 中使用 filter 方法添加过滤。代码如下: /** * 构建筛选条件 */ private void buildFilterQuery(BoolQueryBuilder boolQueryBuilder, Integer type, String category) { // 内容类型筛选 if (type != null) { BoolQueryBuilder typeFilterBuilder = QueryBuilders.boolQuery(); typeFilterBuilder.should(QueryBuilders.matchQuery(SearchConstant.TYPE_NAME, type).lenient(true)); boolQueryBuilder.filter(typeFilterBuilder); } // 内容类别筛选 if (!StringUtils.isEmpty(category)) { BoolQueryBuilder categoryFilterBuilder = QueryBuilders.boolQuery(); categoryFilterBuilder.should(QueryBuilders.matchQuery(SearchConstant.CATEGORY_NAME, category).lenient(true)); boolQueryBuilder.filter(categoryFilterBuilder); } } type 是大类,category 是小类,这样就可以支持 大小类 筛选。但是如果需要在 type = 1 或者 type = 2 中搜索呢?具体实现代码很简单: typeFilterBuilder .should(QueryBuilders.matchQuery(SearchConstant.TYPE_NAME, 1) .should(QueryBuilders.matchQuery(SearchConstant.TYPE_NAME, 2) .lenient(true)); 通过链式表达式,两个 should 实现或,即 SQL 对应的 OR 语句。通过两个 BoolQueryBuilder 实现与,即 SQL 对应的 AND 语句。 五、分页、排序条件 分页排序代码就很简单了: @Override public PageBean searchContent(ContentSearchBean contentSearchBean) { Integer pageNumber = contentSearchBean.getPageNumber(); Integer pageSize = contentSearchBean.getPageSize(); PageBean<ContentEntity> resultPageBean = new PageBean<>(); resultPageBean.setPageNumber(pageNumber); resultPageBean.setPageSize(pageSize); // 构建搜索短语 String searchContent = contentSearchBean.getSearchContent(); List<String> searchTermList = handlingSearchContent(searchContent); // 构建查询条件 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); buildMatchQuery(boolQueryBuilder, searchTermList); // 构建筛选条件 buildFilterQuery(boolQueryBuilder, contentSearchBean.getType(), contentSearchBean.getCategory()); // 构建分页、排序条件 Pageable pageable = PageRequest.of(pageNumber, pageSize); if (!StringUtils.isEmpty(contentSearchBean.getOrderName())) { pageable = PageRequest.of(pageNumber, pageSize, Sort.Direction.DESC, contentSearchBean.getOrderName()); } SearchQuery searchQuery = new NativeSearchQueryBuilder().withPageable(pageable) .withQuery(boolQueryBuilder).build(); // 搜索 LOGGER.info("\n ContentServiceImpl.searchContent() [" + searchContent + "] \n DSL = \n " + searchQuery.getQuery().toString()); Page<ContentEntity> contentPage = contentRepository.search(searchQuery); resultPageBean.setResult(contentPage.getContent()); resultPageBean.setTotalCount((int) contentPage.getTotalElements()); resultPageBean.setTotalPage((int) contentPage.getTotalElements() / resultPageBean.getPageSize() + 1); return resultPageBean; } 利用 Pageable 对象,构造分页参数以及指定对应的 排序字段、排序顺序(DESC ASC)即可。 文章来源:http://mp.weixin.qq.com/s/ZoJzF9VpynUBSQWlJJjmEw
RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。AMQP,即Advanced message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。常用概念通常我们谈到队列服务, 会有三个概念: 发消息者、队列、收消息者,RabbitMQ 在这个基本概念之上, 多做了一层抽象, 在发消息者和 队列之间, 加入了交换器 (Exchange). 这样发消息者和队列就没有直接联系, 转而变成发消息者把消息给交换器, 交换器根据调度策略再把消息再给队列。准备环境安装任选其一CentOs7.3 搭建 RabbitMQ 3.6 单机服务与使用http://www.ymq.io/2017/08/16/rabbit-installCentOs7.3 搭建 RabbitMQ 3.6 Cluster 集群服务与使用http://www.ymq.io/2017/08/17/rabbit-install-clusterGithub 代码代码我已放到 Github ,导入spring-boot-rabbitmq 项目github https://github.com/souyunku/spring-boot-examples/tree/master/spring-boot-rabbitmq添加依赖在项目中添加 spring-boot-starter-amqp 依赖 org.springframework.bootspring-boot-starter-amqp 参数配置 spring.application.name=ymq-rabbitmq-spring-boot spring.rabbitmq.host=10.4.98.15 spring.rabbitmq.port=5672 spring.rabbitmq.username=admin spring.rabbitmq.password=admin 交换机(Exchange)1.Direct Exchange 根据route key 直接找到队列2.Topic Exchange 根据route key 匹配队列3.Topic Exchange 不处理route key 全网发送,所有绑定的队列都发送Direct ExchangeDirect Exchange 是RabbitMQ默认的交换机模式,也是最简单的模式,根据key全文匹配去寻找队列。任何发送到Direct Exchange的消息都会被转发到RouteKey中指定的Queue。1.一般情况可以使用rabbitMQ自带的Exchange:""(该Exchange的名字为空字符串,下文称其为default Exchange)。2.这种模式下不需要将Exchange进行任何绑定(binding)操作3.消息传递时需要一个RouteKey,可以简单的理解为要发送到的队列名字。4.如果vhost中不存在RouteKey中指定的队列名,则该消息会被抛弃。配置队列 @Configurationpublic class RabbitDirectConfig { @Bean public Queue helloQueue() { return new Queue("hello"); } @Bean public Queue directQueue() { return new Queue("direct"); } //-------------------配置默认的交换机模式,可以不需要配置以下----------------------------------- @Bean DirectExchange directExchange() { return new DirectExchange("directExchange"); } //绑定一个key "direct",当消息匹配到就会放到这个队列中 @Bean Binding bindingExchangeDirectQueue(Queue directQueue, DirectExchange directExchange) { return BindingBuilder.bind(directQueue).to(directExchange).with("direct"); } // 推荐使用 helloQueue() 方法写法,这种方式在 Direct Exchange 模式 多此一举,没必要这样写 //---------------------------------------------------------------------------------------------} 监听队列 @Component@RabbitListener(queues = "hello")public class helloReceiver { @RabbitHandler public void process(String message) { System.out.println("接收者 helloReceiver," + message); } } @Component@RabbitListener(queues = "direct")public class DirectReceiver { @RabbitHandler public void process(String message) { System.out.println("接收者 DirectReceiver," + message); } } 发送消息 package io.ymq.rabbitmq.test;import io.ymq.rabbitmq.run.Startup;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.amqp.core.AmqpTemplate;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;/** * 描述: 默认的交换机模式 * * @author: yanpenglei * @create: 2017/10/25 1:03 */@RunWith(SpringRunner.class)@SpringBootTest(classes = Startup.class)public class RabbitDirectTest { @Autowired private AmqpTemplate rabbitTemplate; @Test public void sendHelloTest() { String context = "此消息在,默认的交换机模式队列下,有 helloReceiver 可以收到"; String routeKey = "hello"; context = "routeKey:" + routeKey + ",context:" + context; System.out.println("sendHelloTest : " + context); this.rabbitTemplate.convertAndSend(routeKey, context); } @Test public void sendDirectTest() { String context = "此消息在,默认的交换机模式队列下,有 DirectReceiver 可以收到"; String routeKey = "direct"; String exchange = "directExchange"; context = "context:" + exchange + ",routeKey:" + routeKey + ",context:" + context; System.out.println("sendDirectTest : " + context); // 推荐使用 sendHello() 方法写法,这种方式在 Direct Exchange 多此一举,没必要这样写 this.rabbitTemplate.convertAndSend(exchange, routeKey, context); } } 按顺序执行:响应 接收者 helloReceiver,routeKey:hello,context:此消息在,默认的交换机模式队列下,有 helloReceiver 可以收到 接收者 DirectReceiver,context:directExchange,routeKey:direct,context:此消息在,默认的交换机模式队列下,有 DirectReceiver 可以收到 Fanout Exchange任何发送到Fanout Exchange 的消息都会被转发到与该Exchange绑定(Binding)的所有Queue上。1.可以理解为路由表的模式2.这种模式不需要 RouteKey3.这种模式需要提前将Exchange与Queue进行绑定,一个Exchange可以绑定多个Queue,一个Queue可以同多个Exchange进行绑定。4.如果接受到消息的Exchange没有与任何Queue绑定,则消息会被抛弃。配置队列 @Configurationpublic class RabbitFanoutConfig { final static String PENGLEI = "fanout.penglei.net"; final static String SOUYUNKU = "fanout.souyunku.com"; @Bean public Queue queuePenglei() { return new Queue(RabbitFanoutConfig.PENGLEI); } @Bean public Queue queueSouyunku() { return new Queue(RabbitFanoutConfig.SOUYUNKU); } /** * 任何发送到Fanout Exchange的消息都会被转发到与该Exchange绑定(Binding)的所有队列上。 */ @Bean FanoutExchange fanoutExchange() { return new FanoutExchange("fanoutExchange"); } @Bean Binding bindingExchangeQueuePenglei(Queue queuePenglei, FanoutExchange fanoutExchange) { return BindingBuilder.bind(queuePenglei).to(fanoutExchange); } @Bean Binding bindingExchangeQueueSouyunku(Queue queueSouyunku, FanoutExchange fanoutExchange) { return BindingBuilder.bind(queueSouyunku).to(fanoutExchange); } } 监听队列 @Component@RabbitListener(queues = "fanout.penglei.net")public class FanoutReceiver1 { @RabbitHandler public void process(String message) { System.out.println("接收者 FanoutReceiver1," + message); } } @Component@RabbitListener(queues = "fanout.souyunku.com")public class FanoutReceiver2 { @RabbitHandler public void process(String message) { System.out.println("接收者 FanoutReceiver2," + message); } } 发送消息 package io.ymq.rabbitmq.test;import io.ymq.rabbitmq.run.Startup;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.amqp.core.AmqpTemplate;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;/** * 描述: 广播模式或者订阅模式队列 * * @author: yanpenglei * @create: 2017/10/25 1:08 */@RunWith(SpringRunner.class)@SpringBootTest(classes = Startup.class)public class RabbitFanoutTest { @Autowired private AmqpTemplate rabbitTemplate; @Test public void sendPengleiTest() { String context = "此消息在,广播模式或者订阅模式队列下,有 FanoutReceiver1 FanoutReceiver2 可以收到"; String routeKey = "topic.penglei.net"; String exchange = "fanoutExchange"; System.out.println("sendPengleiTest : " + context); context = "context:" + exchange + ",routeKey:" + routeKey + ",context:" + context; this.rabbitTemplate.convertAndSend(exchange, routeKey, context); } @Test public void sendSouyunkuTest() { String context = "此消息在,广播模式或者订阅模式队列下,有 FanoutReceiver1 FanoutReceiver2 可以收到"; String routeKey = "topic.souyunku.com"; String exchange = "fanoutExchange"; context = "context:" + exchange + ",routeKey:" + routeKey + ",context:" + context; System.out.println("sendSouyunkuTest : " + context); this.rabbitTemplate.convertAndSend(exchange, routeKey, context); } } 按顺序执行:响应 接收者 FanoutReceiver1,context:fanoutExchange,routeKey:topic.penglei.net,context:此消息在,广播模式或者订阅模式队列下,有 FanoutReceiver1 FanoutReceiver2 可以收到 接收者 FanoutReceiver2,context:fanoutExchange,routeKey:topic.penglei.net,context:此消息在,广播模式或者订阅模式队列下,有 FanoutReceiver1 FanoutReceiver2 可以收到 接收者 FanoutReceiver2,context:fanoutExchange,routeKey:topic.souyunku.com,context:此消息在,广播模式或者订阅模式队列下,有 FanoutReceiver1 FanoutReceiver2 可以收到 接收者 FanoutReceiver1,context:fanoutExchange,routeKey:topic.souyunku.com,context:此消息在,广播模式或者订阅模式队列下,有 FanoutReceiver1 FanoutReceiver2 可以收到 Topic Exchange任何发送到Topic Exchange的消息都会被转发到所有关心RouteKey中指定话题的Queue上1.这种模式较为复杂,简单来说,就是每个队列都有其关心的主题,所有的消息都带有一个标题``(RouteKey),Exchange会将消息转发到所有关注主题能与RouteKey模糊匹配的队列。2.这种模式需要RouteKey,也许要提前绑定Exchange与Queue。3.在进行绑定时,要提供一个该队列关心的主题,如#.log.#表示该队列关心所有涉及log的消息(一个RouteKey为MQ.log.error的消息会被转发到该队列)。4.#表示0个或若干个关键字,表示一个关键字。如topic.能与topic.warn匹配,无法与topic.warn.timeout匹配;但是topic.#能与上述两者匹配。5.同样,如果Exchange没有发现能够与RouteKey匹配的Queue,则会抛弃此消息。 配置队列 @Configurationpublic class RabbitTopicConfig { final static String MESSAGE = "topic.message"; final static String MESSAGES = "topic.message.s"; final static String YMQ = "topic.ymq"; @Bean public Queue queueMessage() { return new Queue(RabbitTopicConfig.MESSAGE); } @Bean public Queue queueMessages() { return new Queue(RabbitTopicConfig.MESSAGES); } @Bean public Queue queueYmq() { return new Queue(RabbitTopicConfig.YMQ); } /** * 交换机(Exchange) 描述:接收消息并且转发到绑定的队列,交换机不存储消息 */ @Bean TopicExchange topicExchange() { return new TopicExchange("topicExchange"); } //綁定队列 queueMessages() 到 topicExchange 交换机,路由键只接受完全匹配 topic.message 的队列接受者可以收到消息 @Bean Binding bindingExchangeMessage(Queue queueMessage, TopicExchange topicExchange) { return BindingBuilder.bind(queueMessage).to(topicExchange).with("topic.message"); } //綁定队列 queueMessages() 到 topicExchange 交换机,路由键只要是以 topic.message 开头的队列接受者可以收到消息 @Bean Binding bindingExchangeMessages(Queue queueMessages, TopicExchange topicExchange) { return BindingBuilder.bind(queueMessages).to(topicExchange).with("topic.message.#"); } //綁定队列 queueYmq() 到 topicExchange 交换机,路由键只要是以 topic 开头的队列接受者可以收到消息 @Bean Binding bindingExchangeYmq(Queue queueYmq, TopicExchange topicExchange) { return BindingBuilder.bind(queueYmq).to(topicExchange).with("topic.#"); } } 监听队列 @Component@RabbitListener(queues = "topic.message")public class TopicReceiver1 { @RabbitHandler public void process(String message) { System.out.println("接收者 TopicReceiver1," + message); } } @Component@RabbitListener(queues = "topic.message.s")public class TopicReceiver2 { @RabbitHandler public void process(String message) { System.out.println("接收者 TopicReceiver2," + message); } } @Component@RabbitListener(queues = "topic.ymq")public class TopicReceiver3 { @RabbitHandler public void process(String message) { System.out.println("接收者 TopicReceiver3," + message); } } 发送消息 package io.ymq.rabbitmq.test;import io.ymq.rabbitmq.run.Startup;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.amqp.core.AmqpTemplate;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;/** * 描述: 配置转发消息模式队列 * * @author: yanpenglei * @create: 2017/10/25 1:20 */@RunWith(SpringRunner.class)@SpringBootTest(classes = Startup.class)public class RabbitTopicTest { @Autowired private AmqpTemplate rabbitTemplate; @Test public void sendMessageTest() { String context = "此消息在,配置转发消息模式队列下, 有 TopicReceiver1 TopicReceiver2 TopicReceiver3 可以收到"; String routeKey = "topic.message"; String exchange = "topicExchange"; context = "context:" + exchange + ",routeKey:" + routeKey + ",context:" + context; System.out.println("sendMessageTest : " + context); this.rabbitTemplate.convertAndSend(exchange, routeKey, context); } @Test public void sendMessagesTest() { String context = "此消息在,配置转发消息模式队列下,有 TopicReceiver2 TopicReceiver3 可以收到"; String routeKey = "topic.message.s"; String exchange = "topicExchange"; context = "context:" + exchange + ",routeKey:" + routeKey + ",context:" + context; System.out.println("sendMessagesTest : " + context); this.rabbitTemplate.convertAndSend(exchange, routeKey, context); } @Test public void sendYmqTest() { String context = "此消息在,配置转发消息模式队列下,有 TopicReceiver3 可以收到"; String routeKey = "topic.ymq"; String exchange = "topicExchange"; context = "context:" + exchange + ",routeKey:" + routeKey + ",context:" + context; System.out.println("sendYmqTest : " + context); this.rabbitTemplate.convertAndSend(exchange, routeKey, context); } } 按顺序执行:响应 接收者 TopicReceiver2,context:topicExchange,routeKey:topic.message,context:此消息在,配置转发消息模式队列下, 有 TopicReceiver1 TopicReceiver2 TopicReceiver3 可以收到 接收者 TopicReceiver1,context:topicExchange,routeKey:topic.message,context:此消息在,配置转发消息模式队列下, 有 TopicReceiver1 TopicReceiver2 TopicReceiver3 可以收到 接收者 TopicReceiver3,context:topicExchange,routeKey:topic.message,context:此消息在,配置转发消息模式队列下, 有 TopicReceiver1 TopicReceiver2 TopicReceiver3 可以收到 接收者 TopicReceiver3,context:topicExchange,routeKey:topic.message.s,context:此消息在,配置转发消息模式队列下,有 TopicReceiver2 TopicReceiver3 可以收到 接收者 TopicReceiver2,context:topicExchange,routeKey:topic.message.s,context:此消息在,配置转发消息模式队列下,有 TopicReceiver2 TopicReceiver3 可以收到 接收者 TopicReceiver3,context:topicExchange,routeKey:topic.ymq,context:此消息在,配置转发消息模式队列下,有 TopicReceiver3 可以收到 更多参考内容:http://www.roncoo.com/article/index?tn=SpringBoot
上一篇文章,讲述了如何通过RestTemplate + Ribbon去消费服务,这篇文章主要讲述如何通过Feign去消费服务。 Feign简介Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单。使用Feign,只需要创建一个接口并注解,它具有可插拔的注解特性,可使用Feign 注解和JAX-RS注解,Feign支持可插拔的编码器和解码器,Feign默认集成了Ribbon,并和Eureka结合,默认实现了负载均衡的效果。 Feign 具有如下特性:可插拔的注解支持,包括Feign注解和JAX-RS注解支持可插拔的HTTP编码器和解码器支持Hystrix和它的Fallback支持Ribbon的负载均衡支持HTTP请求和响应的压缩Feign是一个声明式的Web Service客户端,它的目的就是让Web Service调用更加简单。它整合了Ribbon和Hystrix,从而不再需要显式地使用这两个组件。Feign还提供了HTTP请求的模板,通过编写简单的接口和注解,就可以定义好HTTP请求的参数、格式、地址等信息。接下来,Feign会完全代理HTTP的请求,我们只需要像调用方法一样调用它就可以完成服务请求。 简而言之:Feign能干Ribbon和Hystrix的事情,但是要用Ribbon和Hystrix自带的注解必须要引入相应的jar包才可以。 准备工作Eureka Service导入第三篇文章中的项目:作为服务注册中心spring-cloud-eureka-serviceEureka Provider导入第三篇文章中的项目:作为服务的提供者spring-cloud-eureka-provider-1spring-cloud-eureka-provider-2spring-cloud-eureka-provider-3Feign Consumer服务消费者添加依赖新建项目spring-cloud-feign-consumerpom.xml中引入需要的依赖内容: org.springframework.cloudspring-cloud-starter-feign 开启Feign在工程的启动类中,通过@EnableFeignClients 注解开启Feign的功能: package io.ymq.example.feign.consumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.feign.EnableFeignClients; @EnableFeignClients @EnableDiscoveryClient @SpringBootApplication public class FeignConsumerApplication { public static void main(String[] args) { SpringApplication.run(FeignConsumerApplication.class, args); } } 定义接口通过@FeignClient("服务名"),来指定调用哪个服务。比如在代码中调用了eureka-provider服务的/ 接口,/ 就是调用:服务提供者项目:spring-cloud-eureka-provider-1,spring-cloud-eureka-provider-2,spring-cloud-eureka-provider-3 的home() 方法,代码如下: package io.ymq.example.feign.consumer; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; /** * 描述: 指定这个接口所要调用的 提供者服务名称 "eureka-provider" * * @author yanpenglei * @create 2017-12-06 15:13 **/ @FeignClient("eureka-provider") public interface HomeClient { @GetMapping("/") String consumer(); } 消费方法写一个Controller,消费提供者的home 方法 package io.ymq.example.feign.consumer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * 描述:调用提供者的 `home` 方法 * * @author yanpenglei * @create 2017-12-06 15:26 **/ @RestController public class ConsumerController { @Autowired private HomeClient homeClient; @GetMapping(value = "/hello") public String hello() { return homeClient.consumer(); } } 添加配置完整配置application.yml指定注册中心地址,配置自己的服务名称 eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ spring: application: name: feign-consumer server: port: 9000 测试服务依次启动项目:spring-cloud-eureka-servicespring-cloud-eureka-provider-1spring-cloud-eureka-provider-2spring-cloud-eureka-provider-3spring-cloud-feign-consumer启动该工程后,访问服务注册中心,查看服务是否都已注册成功:http://localhost:8761/负载均衡响应在命令窗口curl http://localhost:9000/hello,发现Feign已经实现负载均衡或者浏览器get 请求http://localhost:9000/hello F5 刷新源码下载GitHub:https://github.com/souyunku/spring-cloud-examples/tree/master/spring-cloud-feign码云:https://gitee.com/souyunku/spring-cloud-examples/tree/master/spring-cloud-feign更多参考文章:http://www.roncoo.com/article/index?tn=SpringCloud
Spring Cloud courseName=Spring+cloud) Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。它是一个基于HTTP和TCP的客户端负载均衡器。它可以通过在客户端中配置ribbonServerList来设置服务端列表去轮询访问以达到均衡负载的作用。 Ribbon是什么?Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。 LB方案分类目前主流的LB方案可分成两类:一种是集中式LB, 即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5, 也可以是软件,如nginx), 由该设施负责把访问请求通过某种策略转发至服务的提供方;另一种是进程内LB,将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。Ribbon就属于后者,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。 Ribbon的主要组件与工作流程微服务架构的核心思想是,一个应用是由多个小的、相互独立的、微服务组成,这些服务运行在自己的进程中,开发和发布都没有依赖。 不同服务通过一些轻量级交互机制来通信,例如 RPC、HTTP 等,服务可独立扩展伸缩,每个服务定义了明确的边界,不同的服务甚至可以采用不同的编程语言来实现,由独立的团队来维护。 简单的来说,一个系统的不同模块转变成不同的服务!而且服务可以使用不同的技术加以实现! Ribbon的核心组件 均为接口类型,有以下几个ServerList用于获取地址列表。它既可以是静态的(提供一组固定的地址),也可以是动态的(从注册中心中定期查询地址列表)。 ServerListFilter仅当使用动态ServerList时使用,用于在原始的服务列表中使用一定策略过虑掉一部分地址。 IRule选择一个最终的服务地址作为LB结果。选择策略有轮询、根据响应时间加权、断路器(当Hystrix可用时)等。 Ribbon在工作时首选会通过ServerList来获取所有可用的服务列表,然后通过ServerListFilter过虑掉一部分地址,最后在剩下的地址中通过IRule选择出一台服务器作为最终结果。 Ribbon提供的主要负载均衡策略介绍简单轮询负载均衡(RoundRobin)以轮询的方式依次将请求调度不同的服务器,即每次调度执行i = (i + 1) mod n,并选出第i台服务器。 随机负载均衡 (Random)随机选择状态为UP的Server加权响应时间负载均衡 (WeightedResponseTime)根据相应时间分配一个weight,相应时间越长,weight越小,被选中的可能性越低。 区域感知轮询负载均衡(ZoneAvoidanceRule)复合判断server所在区域的性能和server的可用性选择server 准备工作本次项目示例,改造第一篇文章中的项目,使用spring-cloud-eureka-service作为服务注册中心,spring-cloud-eureka-provider,复制三分,项目名称依次修改为spring-cloud-eureka-provider-1[1-3] 改造 Provider服务提供者在项目:spring-cloud-eureka-provider-1,spring-cloud-eureka-provider-2,spring-cloud-eureka-provider-3 的启动类,都加入@Value("${server.port}"),修改home()方法, 来区分不同端口的Controller 响应,因为接下来,使用ribbon做均衡需要测试需要使用到 package io.ymq.example.eureka.provider; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @EnableEurekaClient @RestController public class EurekaProviderApplication { @Value("${server.port}") String port; @RequestMapping("/") public String home() { return "Hello world ,port:" + port; } public static void main(String[] args) { SpringApplication.run(EurekaProviderApplication.class, args); } } 修改配置在项目:spring-cloud-eureka-provider-1,spring-cloud-eureka-provider-2,spring-cloud-eureka-provider-3,修改server: port:端口依次为8081,8082,8083 eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ spring: application: name: eureka-provider server: port: 8081 Ribbon Consumer服务消费者添加依赖新建spring-cloud-ribbon-consumer org.springframework.cloudspring-cloud-starter-ribbonorg.springframework.cloudspring-cloud-starter-eureka 开启服务负载均衡在工程的启动类中,通过@EnableDiscoveryClient向服务注册中心注册;并且向程序的ioc注入一个bean: restTemplate并通过@LoadBalanced注解表明这个restRemplate开启负载均衡的功能。 package io.ymq.example.ribbon.consumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @EnableDiscoveryClient @SpringBootApplication public class RibbonConsumerApplication { @LoadBalanced @Bean RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(RibbonConsumerApplication.class, args); } } 消费提供者方法新建ConsumerController 类,调用提供者的hello 方法 package io.ymq.example.ribbon.consumer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; /** * 描述:调用提供者的 `home` 方法 * * @author yanpenglei * @create 2017-12-05 18:53 **/ @RestController public class ConsumerController { @Autowired private RestTemplate restTemplate; @GetMapping(value = "/hello") public String hello() { return restTemplate.getForEntity("http://eureka-provider/", String.class).getBody(); } } 添加配置完整配置application.yml指定服务的注册中心地址,配置自己的服务端口,服务名称 eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ spring: application: name: ribbon-consumer server: port: 9000 测试服务启动服务依次启动项目:spring-cloud-eureka-servicespring-cloud-eureka-provider-1spring-cloud-eureka-provider-2spring-cloud-eureka-provider-3spring-cloud-ribbon-consumer启动该工程后,访问服务注册中心,查看服务是否都已注册成功:http://localhost:8761/ 负载均衡在命令窗口curl http://localhost:9000/hello,发现Ribbon已经实现负载均衡或者浏览器get 请求http://localhost:9000/hello F5 刷新源码下载GitHub:https://github.com/souyunku/spring-cloud-examples/tree/master/spring-cloud-ribbon码云:https://gitee.com/souyunku/spring-cloud-examples/tree/master/spring-cloud-ribbonContact 作者:鹏磊出处:http://www.ymq.io更多参考内容:http://www.roncoo.com/article/index?tn=SpringCloud
Spring Cloud Consul 项目是针对Consul的服务治理实现。Consul是一个分布式高可用的系统,具有分布式、高可用、高扩展性。 Consul 简介 Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置。与其他分布式服务注册与发现的方案,Consul的方案更“一站式” ,内置了服务注册与发现框 架、具有以下性质: 分布一致性协议实现、 健康检查、 Key/Value存储、 多数据中心方案, 不再需要依赖其他工具(比如ZooKeeper等)。 使用起来也较 为简单。Consul使用Go语言编写,因此具有天然可移植性(支持Linux、windows和Mac OS X);安装包仅包含一个可执行文件,方便部署,与Docker等轻量级容器可无缝配合 。 基于 Mozilla Public License 2.0 的协议进行开源. Consul 支持健康检查,并允许 HTTP 和 DNS 协议调用 API 存储键值对. 一致性协议采用 Raft 算法,用来保证服务的高可用. 使用 GOSSIP 协议管理成员和广播消息, 并且支持 ACL 访问控制. Consul 的使用场景 docker 实例的注册与配置共享 coreos 实例的注册与配置共享 vitess 集群 SaaS 应用的配置共享 与 confd 服务集成,动态生成 nginx 和 haproxy 配置文件 Consul 的优势 使用 Raft 算法来保证一致性, 比复杂的 Paxos 算法更直接. 相比较而言, zookeeper 采用的是 Paxos, 而 etcd 使用的则是 Raft. 支持多数据中心,内外网的服务采用不同的端口进行监听。 多数据中心集群可以避免单数据中心的单点故障,而其部署则需要考虑网络延迟, 分片等情况等. zookeeper 和 etcd 均不提供多数据中心功能的支持. 支持健康检查. etcd 不提供此功能. 支持 http 和 dns 协议接口. zookeeper 的集成较为复杂, etcd 只支持 http 协议. 官方提供web管理界面, etcd 无此功能. Consul 的角色 client: 客户端, 无状态, 将 HTTP 和 DNS 接口请求转发给局域网内的服务端集群.server: 服务端, 保存配置信息, 高可用集群, 在局域网内与本地客户端通讯, 通过广域网与其他数据中心通讯. 每个数据中心的 server 数量推荐为 3 个或是 5 个. 由于Spring Cloud Consul项目的实现,我们可以轻松的将基于Spring Boot的微服务应用注册到Consul上,并通过此实现微服务架构中的服务治理。 搭建环境 参考 Spring Cloud 官方文档 Consul 官方文档 要想利用Consul提供的服务实现服务的注册与发现,我们需要搭建Consul Cluster 环境。 在Consul方案中,每个提供服务的节点上都要部署和运行Consul的agent,所有运行Consul agent节点的集合构成Consul Cluster。 Consul agent有两种运行模式:Server和Client。这里的Server和Client只是Consul集群层面的区分,与搭建在Cluster之上 的应用服务无关。 以Server模式运行的Consul agent节点用于维护Consul集群的状态,官方建议每个Consul Cluster至少有3个或以上的运行在Server mode的Agent,Client节点不限。 环境配置如下: Centos 7.3 主机名称 IP 作用 是否允许远程访问 node1 192.168.252.121 consul server 是 node2 192.168.252.122 consul client 是 node3 192.168.252.123 consul client 是 关闭防火墙 systemctl stop firewalld.service Consul 最新版的下载地址: https://releases.hashicorp.com/consul/1.0.1/consul_1.0.1_linux_amd64.zip 下载,然后unzip 解压,得到唯一,一个可执行文件 cd /opt/ wget https://releases.hashicorp.com/consul/1.0.1/consul_1.0.1_linux_amd64.zip unzip consul_1.0.1_linux_amd64.zip cp consul /usr/local/bin/ 查看是否安装成功 [root@node1 opt]# consul 出现如下结果,表示安装成功 Usage: consul [--version] [--help][]Available commands are: agent Runs a Consul agent catalog Interact with the catalog event Fire a new event exec Executes a command on Consul nodes force-leave Forces a member of the cluster to enter the "left" state info Provides debugging information for operators. join Tell Consul agent to join cluster keygen Generates a new encryption key keyring Manages gossip layer encryption keys kv Interact with the key-value store leave Gracefully leaves the Consul cluster and shuts down lock Execute a command holding a lock maint Controls node or service maintenance mode members Lists the members of a Consul cluster monitor Stream logs from a Consul agent operator Provides cluster-level tools for Consul operators reload Triggers the agent to reload configuration files rtt Estimates network round trip time between nodes snapshot Saves, restores and inspects snapshots of Consul server state validate Validate config files/directories version Prints the Consul version watch Watch for changes in Consul 检查版本 [root@node1 opt]# consul version Consul v1.0.1 Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents) Consul常用命令 命令 解释 示例 agent 运行一个consul agent consul agent -dev join 将agent加入到consul集群 consul join IP members 列出consul cluster集群中的members consul members leave 将节点移除所在集群 consul leave consul agent 命令的常用选项 -data-dir 作用:指定agent储存状态的数据目录 这是所有agent都必须的 对于server尤其重要,因为他们必须持久化集群的状态 -config-dir 作用:指定service的配置文件和检查定义所在的位置 通常会指定为”某一个路径/consul.d”(通常情况下,.d表示一系列配置文件存放的目录) -config-file 作用:指定一个要装载的配置文件 该选项可以配置多次,进而配置多个配置文件(后边的会合并前边的,相同的值覆盖) -dev 作用:创建一个开发环境下的server节点 该参数配置下,不会有任何持久化操作,即不会有任何数据写入到磁盘 这种模式不能用于生产环境(因为第二条) -bootstrap-expect 作用:该命令通知consul server我们现在准备加入的server节点个数,该参数是为了延迟日志复制的启动直到我们指定数量的server节点成功的加入后启动。 -node 作用:指定节点在集群中的名称 该名称在集群中必须是唯一的(默认采用机器的host) 推荐:直接采用机器的IP -bind 作用:指明节点的IP地址 有时候不指定绑定IP,会报Failed to get advertise address: Multiple private IPs found. Please configure one.的异常 -server 作用:指定节点为server 每个数据中心(DC)的server数推荐至少为1,至多为5 所有的server都采用raft一致性算法来确保事务的一致性和线性化,事务修改了集群的状态,且集群的状态保存在每一台server上保证可用性 server也是与其他DC交互的门面(gateway) -client 作用:指定节点为client,指定客户端接口的绑定地址,包括:HTTP、DNS、RPC 默认是127.0.0.1,只允许回环接口访问 若不指定为-server,其实就是-client -join 作用:将节点加入到集群 -datacenter(老版本叫-dc,-dc已经失效) 作用:指定机器加入到哪一个数据中心中 启动服务 我们尝试一下: -dev表示开发模式运行,使用-client 参数可指定允许客户端使用什么ip去访问,例如-client 192.168.252.121 表示可以使用 http://192.168.252.121:8500/ui/ 去访问。 consul agent -dev -client 192.168.252.121 Consul 的高可用 Consul Cluster集群架构图如下: 这边准备了三台Centos 7.3的虚拟机,主机规划如下,供参考: 主机名称 IP 作用 是否允许远程访问 node1 192.168.252.121 consul server 是 node2 192.168.252.122 consul client 是 node3 192.168.252.123 consul client 是 搭建步骤 命令参数,参看上面详细介绍 在 node1 机器上启动 Consul cd /opt/ mkdir data consul agent -data-dir /opt/data -node=192.168.252.121 -bind=0.0.0.0 -datacenter=dc1 -ui -client=192.168.252.121 -server -bootstrap-expect 1 > /dev/null 2>&1 & 在 node2 机器上启动 Consul,并且将node2节点加入到node1节点上 cd /opt/ mkdir data consul agent -data-dir /opt/data -node=192.168.252.122 -bind=0.0.0.0 -datacenter=dc1 -ui -client=192.168.252.122 -join=192.168.252.121 > /dev/null 2>&1 & 在 node3 机器上启动 Consul,并且将node3节点加入到node1节点上 cd /opt/ mkdir data consul agent -data-dir /opt/data -node=192.168.252.123 -bind=0.0.0.0 -datacenter=dc1 -ui -client=192.168.252.123 -join=192.168.252.121 > /dev/null 2>&1 & 在node1上查看当前集群节点: consul members -rpc-addr=192.168.252.123:8400 consul leave -rpc-addr=192.168.252.123:8400 http://192.168.252.121:8500/ui/ 去访问。 项目示例 新建项目:spring-cloud-consul-client 添加依赖 在项目spring-cloud-consul-clientpom.xml中引入需要的依赖内容: org.springframework.cloudspring-cloud-starter-consul-discovery 开启服务注册 客户端注册Consul时,它提供有关自身的元数据,如主机和端口,ID,名称和标签。默认情况下,将创建一个HTTP 检查,每隔10秒Consul命中/health端点。如果健康检查失败,则服务实例被标记为关键。 package io.ymq.example.consul; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @EnableDiscoveryClient @RestController public class ConsulApplication { @RequestMapping("/") public String home() { return "Hello world"; } public static void main(String[] args) { SpringApplication.run(ConsulApplication.class, args); } } 配置文件 在application.yml配置文件中增加如下信息:如果Consul客户端位于localhost:8500以外,则需要配置来定位客户端 spring: application: name: consul-client cloud: consul: host: 192.168.252.121 port: 8500 discovery: healthCheckPath: / healthCheckInterval: 5s 如果Consul客户端位于localhost:8500以外的位置,则需要配置来定位客户端。例: host: 192.168.252.121port: 8500 HTTP健康检查路径 INSTALL “10s”和“1m”分别表示10秒和1分 discovery: healthCheckPath: ${management.context-path}/health healthCheckInterval: 15s 启动服务 到spring-cloud-consul-client项目根目录下,执行mvn clean package,把target目录下 生成的 jarspring-cloud-consul-client-0.0.1-SNAPSHOT.jar上传服务器,发布项目 打包命令 mvn clean package 发布命令 nohup java -jar spring-cloud-consul-client-0.0.1-SNAPSHOT.jar > /dev/null 2>&1 & 访问服务 http://192.168.252.121:8500/ui/#/dc1/nodes/192.168.252.121 通过上图HTTP健康检查,可以看到服务检测正常 源码下载 GitHub:https://github.com/souyunku/spring-cloud-examples/tree/master/spring-cloud-consul 码云:https://gitee.com/souyunku/spring-cloud-examples/tree/master/spring-cloud-consul 更多参考内容:http://www.roncoo.com/article/index?tn=SpringCloud
Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中涉及的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了一种简单的开发方式。 Spring Cloud简介Spring Cloud包含了多个子项目(针对分布式系统中涉及的多个不同开源产品),比如:Spring Cloud Config、Spring Cloud Netflix、Spring Cloud0 CloudFoundry、Spring Cloud AWS、Spring Cloud Security、Spring Cloud Commons、Spring Cloud Zookeeper、Spring Cloud CLI等项目。 微服务架构微服务(Microservices Architecture)是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好地完成该任务。在所有情况下,每个任务代表着一个小的业务能力。 微服务的概念源于2014年3月Martin Fowler所写的章“Microservices”http://martinfowler.com/articles/microservices.html微服务架构(Microservices Architecture)微服务架构的核心思想是,一个应用是由多个小的、相互独立的、微服务组成,这些服务运行在自己的进程中,开发和发布都没有依赖。不同服务通过一些轻量级交互机制来通信,例如 RPC、HTTP 等,服务可独立扩展伸缩,每个服务定义了明确的边界,不同的服务甚至可以采用不同的编程语言来实现,由独立的团队来维护。简单的来说,一个系统的不同模块转变成不同的服务!而且服务可以使用不同的技术加以实现! 微服务设计那我们在微服务中应该怎样设计呢。以下是微服务的设计指南:职责单一原则(Single Responsibility Principle):把某一个微服务的功能聚焦在特定业务或者有限的范围内会有助于敏捷开发和服务的发布。 设计阶段就需要把业务范围进行界定。需要关心微服务的业务范围,而不是服务的数量和规模尽量小。数量和规模需要依照业务功能而定。 于SOA不同,某个微服务的功能、操作和消息协议尽量简单。项目初期把服务的范围制定相对宽泛,随着深入,进一步重构服务,细分微服务是个很好的做法。 关于微服务架构的取舍在合适的项目,合适的团队,采用微服务架构收益会大于成本。微服务架构有很多吸引人的地方,但在拥抱微服务之前,也需要认清它所带来的挑战。 需要避免为了“微服务”而“微服务”。微服务架构引入策略 – 对传统企业而言,开始时可以考虑引入部分合适的微服务架构原则对已有系统进行改造或新建微服务应用,逐步探索及积累微服务架构经验,而非全盘实施微服务架构。 更多关于微服务架构内容-请参考我的另一篇文章:《什什么是微服务架构?》 服务治理由于Spring Cloud为服务治理做了一层抽象接口,所以在Spring Cloud应用中可以支持多种不同的服务治理框架,比如:Netflix Eureka、Consul、Zookeeper。在Spring Cloud服务治理抽象层的作用下,我们可以无缝地切换服务治理实现,并且不影响任何其他的服务注册、服务发现、服务调用等逻辑。 Spring Cloud EurekaSpring Cloud Eureka来实现服务治理。Spring Cloud Eureka是Spring Cloud Netflix项目下的服务治理模块。而Spring Cloud Netflix项目是Spring Cloud的子项目之一,主要内容是对Netflix公司一系列开源产品的包装,它为Spring Boot应用提供了自配置的Netflix OSS整合。通过一些简单的注解,开发者就可以快速的在应用中配置一下常用模块并构建庞大的分布式系统。它主要提供的模块包括:服务发现(Eureka),断路器(Hystrix),智能路由(Zuul),客户端负载均衡(Ribbon)等。 Eureka Server提供服务注册和发现添加依赖在项目 spring-cloud-eureka-service pom.xml中引入需要的依赖内容: org.springframework.cloud spring-cloud-starter-eureka-server 开启服务注册通过 @EnableEurekaServer 注解启动一个服务注册中心提供给其他应用进行对话,这个注解需要在springboot工程的启动application类上加 package io.ymq.example.eureka.server; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } } 添加配置在默认设置下,该服务注册中心也会将自己作为客户端来尝试注册它自己,所以我们需要禁用它的客户端注册行为,只需要在 application.yml配置文件中增加如下信息: registerWithEureka: false fetchRegistry: false 完整配置 server: port: 8761 eureka: instance: hostname: localhost client: registerWithEureka: false fetchRegistry: false serviceUrl: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ 访问服务启动工程后,访问:http://localhost:8761/可以看到下面的页面,其中还没有发现任何服务。 Service Provider服务提供方将自身服务注册到 Eureka 注册中心,从而使服务消费方能够找到添加依赖在项目 spring-cloud-eureka-provider pom.xml中引入需要的依赖内容: org.springframework.cloud spring-cloud-starter-eureka-server 开启服务注册在应用主类中通过加上 @EnableEurekaClient,但只有Eureka 可用,你也可以使用@EnableDiscoveryClient。需要配置才能找到Eureka注册中心服务器 package io.ymq.example.eureka.provider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @EnableEurekaClient @RestController public class EurekaProviderApplication { @RequestMapping("/") public String home() { return "Hello world"; } public static void main(String[] args) { SpringApplication.run(EurekaProviderApplication.class, args); } } 添加配置需要配置才能找到Eureka服务器。例:完整配置 eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ spring: application: name: eureka-provider server: port: 8081 其中 defaultZone是一个魔术字符串后备值,为任何不表示首选项的客户端提供服务URL(即它是有用的默认值)。 通过 spring.application.name属性,我们可以指定微服务的名称后续在调用的时候只需要使用该名称就可以进行服务的访问访问服务启动该工程后,再次访问启动工程后:http://localhost:8761/可以如下图内容,我们定义的服务被成功注册了。源码下载GitHub:https://github.com/souyunku/spring-cloud-examples/tree/master/spring-cloud-eureka码云:https://gitee.com/souyunku/spring-cloud-examples/tree/master/spring-cloud-eureka 文章来源:http://www.roncoo.com/article/detail/131693更多参考内容:http://www.roncoo.com/article/index?tn=SpringCloud
环境 操作系统:CentOS-6.6-x86_64-bin-DVD1.iso MySQL版本:mysql-5.6.26.tar.gz 主节点IP:192.168.1.205 主机名:edu-mysql-01 从节点IP:192.168.1.206 主机名:edu-mysql-02 主机配置:4核CPU、4G内存 依赖课程 《高可用架构篇--第13节--MySQL源码编译安装(CentOS-6.6+MySQL-5.6)》 MySQL主从复制官方文档 http://dev.mysql.com/doc/refman/5.6/en/replication.html MySQL主从复制的方式 MySQL5.6开始主从复制有两种方式:基于日志(binlog)、基于GTID(全局事务标示符)。 本教程主要讲基于日志(binlog)的复制。 MySQL主从复制(也称A/B复制)的原理 (1) Master将数据改变记录到二进制日志(binary log)中,也就是配置文件log-bin指定的文件,这些记录叫做二进制日志事件(binary log events); (2) Slave通过I/O线程读取Master中的binary log events并写入到它的中继日志(relay log); (3) Slave重做中继日志中的事件,把中继日志中的事件信息一条一条的在本地执行一次,完成数据在本地的存储,从而实现将改变反映到它自己的数据(数据重放)。 主从配置需要注意的点 (1)主从服务器操作系统版本和位数一致; (2) Master和Slave数据库的版本要一致; (3) Master和Slave数据库中的数据要一致; (4) Master开启二进制日志,Master和Slave的server_id在局域网内必须唯一; 主从配置的简要步骤 1、Master上的配置 (1) 安装数据库; (2) 修改数据库配置文件,指明server_id,开启二进制日志(log-bin); (3) 启动数据库,查看当前是哪个日志,position号是多少; (4) 登录数据库,授权数据复制用户(IP地址为从机IP地址,如果是双向主从,这里的还需要授权本机的IP地址,此时自己的IP地址就是从IP地址); (5) 备份数据库(记得加锁和解锁); (6) 传送备份数据到Slave上; (7) 启动数据库; 以下步骤,为单向主从搭建成功,想搭建双向主从需要的步骤: (1) 登录数据库,指定Master的地址、用户、密码等信息(此步仅双向主从时需要); (2) 开启同步,查看状态; 2、Slave上的配置 (1) 安装数据库; (2) 修改数据库配置文件,指明server_id(如果是搭建双向主从的话,也要开启二进制日志log-bin); (3) 启动数据库,还原备份; (4) 查看当前是哪个日志,position号是多少(单向主从此步不需要,双向主从需要); (5) 指定Master的地址、用户、密码等信息; (6) 开启同步,查看状态。 单向主从环境(也称MySQL A/B复制)的搭建 1、Master(192.168.1.205)和Slave(192.168.1.206)上都安装了相同版本的数据库(mysql-5.6.26.tar.gz),参考《高可用架构篇--第13节--MySQL源码编译安装(CentOS6.6+MySQL5.6)》。 注意:两台数据库服务器的的selinux都要disable(永久关闭selinux,请修改/etc/selinux/config,将SELINUX改为disabled) 2、修改Master的配置文件/etc/my.cnf [root@edu-mysql-01 ~]# vi /etc/my.cnf ## 在 [mysqld] 中增加以下配置项 ## 设置server_id,一般设置为IP server_id=205 ## 复制过滤:需要备份的数据库,输出binlog #binlog-do-db=roncoo ## 复制过滤:不需要备份的数据库,不输出(mysql库一般不同步) binlog-ignore-db=mysql ## 开启二进制日志功能,可以随便取,最好有含义 log-bin=edu-mysql-bin ## 为每个session 分配的内存,在事务过程中用来存储二进制日志的缓存 binlog_cache_size=1M ## 主从复制的格式(mixed,statement,row,默认格式是statement) binlog_format=mixed ## 二进制日志自动删除/过期的天数。默认值为0,表示不自动删除。 expire_logs_days=7 ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。 ## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致 slave_skip_errors=1062 (如想了解以上参数的更多详细解析,大家可以直接百度参数名) 2.1 复制过滤可以让你只复制服务器中的一部分数据,有两种复制过滤: (1) 在Master上过滤二进制日志中的事件; (2) 在Slave上过滤中继日志中的事件。如下: 2.2 MySQL对于二进制日志 (binlog)的复制类型 (1) 基于语句的复制:在Master上执行的SQL语句,在Slave上执行同样的语句。MySQL默认采用基于语句的复制,效率比较高。一旦发现没法精确复制时,会自动选着基于行的复制。 (2) 基于行的复制:把改变的内容复制到Slave,而不是把命令在Slave上执行一遍。从MySQL5.0开始支持。 (3) 混合类型的复制:默认采用基于语句的复制,一旦发现基于语句的无法精确的复制时,就会采用基于行的复制。 3、启动/重启Master数据库服务,登录数据库,创建数据同步用户,并授予相应的权限 [root@edu-mysql-01 ~]# service mysql restart Shutting down MySQL..[ OK ] Starting MySQL..[ OK ] [root@edu-mysql-01 ~]# mysql -uroot -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.6.26-log Source distribution Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. ##创建数据同步用户,并授予相应的权限 mysql> grant replication slave, replication client on *.* to 'repl'@'192.168.1.206' identified by 'roncoo.123'; Query OK, 0 rows affected (0.00 sec) ## 刷新授权表信息 mysql> flush privileges; Query OK, 0 rows affected (0.00 sec) ## 查看position号,记下position号(从机上需要用到这个position号和现在的日志文件) mysql> show master status; 4、创建roncoo库、表,并写入一定量的数据,用于模拟现有的业务系统数据库 create database if not exists roncoo default charset utf8 collate utf8_general_ci; use roncoo; DROP TABLE IF EXISTS `edu_user`; CREATE TABLE `edu_user` ( `Id` int(11) NOT NULL AUTO_INCREMENT, `userName` varchar(255) NOT NULL DEFAULT '' COMMENT '用户名', `pwd` varchar(255) NOT NULL DEFAULT '' COMMENT '密码', PRIMARY KEY (`Id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='用户信息表'; INSERT INTO `edu_user` VALUES (1,'吴水成','123456'),(2,'清风','123456'),(3,'龙果','roncoo.com'); 5、为保证Master和Slave的数据一致,我们采用主备份,从还原来实现初始数据一致 ## 先临时锁表 mysql> flush tables with read lock; Query OK, 0 rows affected (0.00 sec) ## 这里我们实行全库备份,在实际中,我们可能只同步某一个库,那也可以只备份一个库 [root@edu-mysql-01 ~]# mysqldump -p3306 -uroot -p --add-drop-table roncoo > /tmp/edu-master-roncoo.sql; Warning: Using a password on the command line interface can be insecure. Enter password: [root@edu-mysql-01 ~]# cd /tmp [root@edu-mysql-01 tmp]# ll total 644 -rw-r--r-- 1 root root 644266 Dec 20 04:10 edu-master-roncoo.sql ## 注意:实际生产环境中大数据量(超2G数据)的备份,建议不要使用mysqldump进行比分,因为会非常慢。此时推荐使用 XtraBackup 进行备份。 ## 解锁表 mysql> unlock tables; Query OK, 0 rows affected (0.00 sec) 将Master上备份的数据远程传送到Slave上,以用于Slave配置时恢复数据 [root@edu-mysql-01 ~]# scp /tmp/edu-master-roncoo.sql root@192.168.1.206:/tmp/ root@192.168.1.206's password: edu-master-roncoo.sql 100% 629KB 629.2KB/s 00:00 [root@edu-mysql-01 ~]# 6、接下来处理Slave(192.168.1.206),配置文件只需修改一项,其余配置用命令来操作 [root@edu-mysql-02 ~]# vi /etc/my.cnf ## 在 [mysqld] 中增加以下配置项 ## 设置server_id,一般设置为IP server_id=206 ## 复制过滤:需要备份的数据库,输出binlog #binlog-do-db=roncoo ##复制过滤:不需要备份的数据库,不输出(mysql库一般不同步) binlog-ignore-db=mysql ## 开启二进制日志,以备Slave作为其它Slave的Master时使用 log-bin=edu-mysql-slave1-bin ## 为每个session 分配的内存,在事务过程中用来存储二进制日志的缓存 binlog_cache_size = 1M ## 主从复制的格式(mixed,statement,row,默认格式是statement) binlog_format=mixed ## 二进制日志自动删除/过期的天数。默认值为0,表示不自动删除。 expire_logs_days=7 ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。 ## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致 slave_skip_errors=1062 ## relay_log配置中继日志 relay_log=edu-mysql-relay-bin ## log_slave_updates表示slave将复制事件写进自己的二进制日志 log_slave_updates=1 ## 防止改变数据(除了特殊的线程) read_only=1 如果Slave为其它Slave的Master时,必须设置bin_log。在这里,我们开启了二进制日志,而且显式的命名(默认名称为hostname,但是,如果hostname改变则会出现问题)。 relay_log配置中继日志,log_slave_updates表示slave将复制事件写进自己的二进制日志。 当设置log_slave_updates时,你可以让slave扮演其它slave的master。此时,slave把SQL线程执行的事件写进行自己的二进制日志(binary log),然后,它的slave可以获取这些事件并执行它。如下图所示(发送复制事件到其它Slave): 7、保存后重启MySQL服务,还原备份数据 [root@edu-mysql-02 ~]# service mysql restart Shutting down MySQL..[ OK ] Starting MySQL..[ OK ] Slave上创建相同库: create database if not exists roncoo default charset utf8 collate utf8_general_ci; use roncoo; 导入数据 [root@edu-mysql-02 ~]# mysql -uroot -p roncoo < /tmp/edu-master-roncoo.sql Enter password: [root@edu-mysql-02 ~]# 8、登录Slave数据库,添加相关参数 (Master的IP、端口、同步用户、密码、position号、读取哪个日志文件) [root@edu-mysql-02 ~]# mysql -uroot -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 3 Server version: 5.6.26-log Source distribution Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> change master to master_host='192.168.1.205', master_user='repl', master_password='roncoo.123', master_port=3306, master_log_file='edu-mysql-bin.000001', master_log_pos=1389, master_connect_retry=30; Query OK, 0 rows affected, 2 warnings (0.01 sec) 上面执行的命令的解释: master_host='192.168.1.205' ## Master的IP地址 master_user='repl' ## 用于同步数据的用户(在Master中授权的用户) master_password='roncoo.123' ## 同步数据用户的密码 master_port=3306 ## Master数据库服务的端口 master_log_file='edu-mysql-bin.000001' ##指定Slave从哪个日志文件开始读复制数据(可在Master上使用show master status查看到日志文件名) master_log_pos=429 ## 从哪个POSITION号开始读 master_connect_retry=30 ##当重新建立主从连接时,如果连接建立失败,间隔多久后重试。单位为秒,默认设置为60秒,同步延迟调优参数。 ## 查看主从同步状态 mysql> show slave status\G; 可看到Slave_IO_State为空, Slave_IO_Running和Slave_SQL_Running是No,表明Slave还没有开始复制过程。 ## 开启主从同步 mysql> start slave; Query OK, 0 rows affected (0.00 sec) ## 再查看主从同步状态 mysql> show slave status\G; 主要看以下两个参数,这两个参数如果是Yes就表示主从同步正常 Slave_IO_Running: Yes Slave_SQL_Running: Yes 由截图中的主从同步状态信息可以看出,我们配置的主从同步是正常的。 可查看master和slave上线程的状态。在master上,可以看到slave的I/O线程创建的连接: Master : mysql> show processlist\G; 1.row 为处理slave的I/O线程的连接。 2.row 为处理MySQL客户端连接线程。 3.row 为处理本地命令行的线程。 Slave : mysql> show processlist\G; 1.row 为I/O线程状态。 2.row 为SQL线程状态。 3.row 为处理本地命令行的线程。 9、主从数据复制同步测试 (1) 在Master中的roncoo库上变更数据的同步测试; mysql> INSERT INTO `edu_user` VALUES (4,'同步测试1','123456'),(5,'同步测试2','123456'); Master中添加完之后,登录Slave中查看数据是否已同步。 (2) 在Master上新建一个ron库 mysql> create database if not exists ron default charset utf8 collate utf8_general_ci; 在Slave中查看数据库 mysql> show databases; 最终的测试结果是,在Master中的操作,都成功同步到了Slave。 10、测试过程中,如果遇到同步出错,可在Slave上重置主从复制设置(选操作): (1) mysql> reset slave; (2) mysql> change master to master_host='192.168.1.205', master_user='repl', master_password='roncoo.123', master_port=3306, master_log_file='edu-mysql-bin.00000x', master_log_pos=xx, master_connect_retry=30; (此时,master_log_file和master_log_pos要在Master中用show master status 命令查看) 注意:如果在Slave没做只读控制的情况下,千万不要在Slave中手动插入数据,那样数据就会不一致,主从就会断开,就需要重新配置了。 11、上面所搭建的是单向复制的主从,也是用的比较多的,而双向主从其实就是Master和Slave都开启日志功能,然后在Master执行授权用户(这里授权的是自己作为从服务器,也就是这里的IP地址是Master的IP地址),然后再在Master上进行chang master操作。 MySQL主从数据同步延迟问题的调优 基于局域网的Master/Slave机制在通常情况下已经可以满足“实时”备份的要求了。如果延迟比较大,可以从以下几个因素进行排查: (1) 网络延迟; (2) Master负载过高; (3) Slave负载过高; 一般的做法是使用多台Slave来分摊读请求,再单独配置一台Slave只作为备份用,不进行其他任何操作,就能相对最大限度地达到“实时”的要求了。 两个可以减少主从复制延迟的参数(按需配置): MySQL可以指定3个参数,用于复制线程重连主库:--master-retry-count,--master-connect-retry,--slave-net-timeout 。其中 master-connect-retry 和 master-retry-count 需要在 Change Master 搭建主备复制时指定,而 slave-net-timeout 是一个全局变量,可以在 MySQL 运行时在线设置。具体的重试策略为:备库过了 slave-net-timeout 秒还没有收到主库来的数据,它就会开始第一次重试。然后每过 master-connect-retry 秒,备库会再次尝试重连主库。直到重试了 master-retry-count 次,它才会放弃重试。如果重试的过程中,连上了主库,那么它认为当前主库是好的,又会开始 slave-net-timeout 秒的等待。slave-net-timeout 的默认值是 3600 秒,master-connect-retry 默认为 60 秒,master-retry-count 默认为 86400 次。也就是说,如果主库一个小时都没有任何数据变更发送过来,备库才会尝试重连主库。这就是为什么在我们模拟的场景下,一个小时后,备库才会重连主库,继续同步数据变更的原因。 这样的话,如果你的主库上变更比较频繁,可以考虑将 slave-net-timeout 设置的小一点,避免主库 Binlog dump 线程终止了,无法将最新的更新推送过来。当然 slave-net-timeout 设置的过小也有问题,这样会导致如果主库的变更确实比较少的时候,备库频繁的重新连接主库,造成资源浪费。 slave-net-timeout=seconds 参数说明:当Slave从Master数据库读取log数据失败后,等待多久重新建立连接并获取数据,单位为秒,默认设置为3600秒。 在做MySQL Slave的时候经常会遇到很多错误,需要根据具体原因跨过错误继续同步,但有时候是因为网络不稳定、网络闪断造成同步不正常,如果Slave机器非常多的情况下,一个一个登录服务器去stop slave、start slave变得无聊而且重复。从MySQL5.1开始支持的解决方案配置: master-connect-retry=seconds 参数说明:在主服务器宕机或连接丢失的情况下,从服务器线程重新尝试连接主服务器之前睡眠的秒数。如果主服务器.info文件中的值可以读取则优先使用。如果未设置,默认值为60。 通常配置以上2个参数可以减少网络问题导致的主从数据同步延迟。 一般网络问题的错误是: [ERROR] Error reading packet from server: Lost connection to MySQL server during query (server_errno=xxxx) [ERROR] Slave I/O thread: Failed reading log event, reconnecting to retry, log ‘edu-mysql-bin.000256’ position 23456 推荐参考链接: http://www.it165.net/database/html/201311/4851.html http://blog.csdn.net/hguisu/article/details/7325124 http://www.woqutech.com/?p=1116 http://blog.chinaunix.net/uid-10661836-id-4116512.html http://my.oschina.net/cimu/blog/165019 http://linuxguest.blog.51cto.com/195664/686813/ http://blog.itpub.net/29096438/viewspace-1409405/ http://blog.csdn.net/lxpbs8851/article/details/38455223 http://blog.csdn.net/seteor/article/details/17264633
部署环境 操作系统:CentOS-6.6-x86_64-bin-DVD1.iso MySQL版本:mysql-5.6.26.tar.gz 操作用户:root 系统IP:192.168.1.205 主机名:edu-mysql-01 配置:4核、4G内存 一、服务器配置: 1、配置网络 # vi /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE=eth0 BOOTPROTO=static NM_CONTROLLED=no ONBOOT=yes TYPE=Ethernet HWADDR=00:50:56:a1:12:53 IPADDR=192.168.1.205 NETMASK=255.255.255.0 GATEWAY=192.168.1.1 DNS1=223.5.5.5 DNS2=223.6.6.6 2、设置主机名 # vi /etc/sysconfig/network NETWORKING=yes HOSTNAME=edu-mysql-01 3、设置IP与主机名的映射 # vi /etc/hosts 127.0.0.1 edu-mysql-01 192.168.1.205 edu-mysql-01 4、两台数据库服务器的的selinux都要disable (永久关闭selinux,请修改/etc/selinux/config,将SELINUX改为disabled) # vi /etc/selinux/config SELINUX=disabled 5、重启操作系统 # reboot 二、源码安装MySQL5.6.26: 1、使用下面的命令检查是否安装有MySQL Server: # rpm -qa | grep mysql mysql-libs-5.1.73-3.el6_5.x86_64 如果是CentOS7以上,请使用以下命令查看: # rpm -qa | grep mariadb mariadb-libs-5.5.41-2.el7_0.x86_64 (因为没有MySQL服务,因此没必要卸载。mysql-libs是MySQL的必要包) (如果有的话可通过下面的命令来卸载掉,rpm -e mysql //普通删除模式) 2、改防火墙设置,打开3306端口: # vi /etc/sysconfig/iptables 增加如下行: ## MySQL -A INPUT -p tcp -m state --state NEW -m tcp --dport 3306 -j ACCEPT 重启防火墙: # service iptables restart 3、新增mysql用户组: # groupadd mysql 4、新增mysql用户,并添加到mysql用户组: # useradd -r -g mysql mysql 5、新建MySQL执行文件目录(后面会把编译好的mysql程序安装到这个目录): # mkdir -p /usr/local/mysql (-p 参数的作用是:如果最终目录的父目录不存在也会一并创建) 6、新建MySQL数据库数据文件目录: # mkdir -p /home/mysql/data # mkdir -p /home/mysql/logs # mkdir -p /home/mysql/temp (注意:上面的logs及temp目录是为了以后将MySQL的数据文件与执行程序文件分离,如果你打算设置到不同的路径,注意修改对应的执行命令和数据库初始化脚本。正式生产环境,建议数据目录和日志目录都使用单独的分区来挂载,不同分区属于不同的磁盘或磁盘组。) 7、增加PATH环境变量搜索路径: # vi /etc/profile ##在profile文件末尾增加两行 # mysql env param PATH=/usr/local/mysql/bin:/usr/local/mysql/lib:$PATH export PATH 使PATH搜索路径立即生效: # source /etc/profile 8、安装编译MySQL需要的依赖包: (mysql从5.5版本开始,不再使用./configure编译,而是使用cmake编译器,具体的cmake编译参数可以参考mysql官网文档 http://dev.mysql.com/doc/refman/5.5/en/source-configuration-options.html,安装基本依赖包,先用yum安装cmake、automake 、autoconf ,另MySQL 5.5.x需要最少安装的包有:bison,gcc、gcc-c++、ncurses-devel): # yum install make cmake gcc gcc-c++ bison bison-devel ncurses ncurses-devel autoconf automake 9、进入/usr/local/src目录,上传mysql-5.6.26.tar.gz源代码到/usr/local/src目录: # cd /usr/local/src 10、开始编译安装mysql-5.6.26: 解压缩源码包: # tar -zxvf mysql-5.6.26.tar.gz 进入解压缩源码目录: # cd mysql-5.6.26 使用cmake源码安装mysql(如果你打算安装到不同的路径,注意修改下面语句中/usr/local/mysql和/home/mysql/data路径!) [root@edu-mysql-01 mysql-5.6.26]# cmake \ -DCMAKE_INSTALL_PREFIX=/usr/local/mysql \ -DMYSQL_UNIX_ADDR=/usr/local/mysql/mysql.sock \ -DDEFAULT_CHARSET=utf8 \ -DDEFAULT_COLLATION=utf8_general_ci \ -DWITH_MYISAM_STORAGE_ENGINE=1 \ -DWITH_INNOBASE_STORAGE_ENGINE=1 \ -DWITH_ARCHIVE_STORAGE_ENGINE=1 \ -DWITH_BLACKHOLE_STORAGE_ENGINE=1 \ -DWITH_MEMORY_STORAGE_ENGINE=1 \ -DWITH_READLINE=1 \ -DENABLED_LOCAL_INFILE=1 \ -DMYSQL_DATADIR=/home/mysql/data \ -DMYSQL_USER=mysql \ -DMYSQL_TCP_PORT=3306 \ -DENABLE_DOWNLOADS=1 上面的这些复制完,回车,然后就开始cmake的过程,一般时间不会很长。 配置解释: -DCMAKE_INSTALL_PREFIX=/usr/local/mysql 设置安装目录 -DMYSQL_DATADIR=/home/mysql/data 设置数据库存放目录 -DMYSQL_UNIX_ADDR=/usr/local/mysql/mysql.sock 设置UNIX socket 目录 -DMYSQL_USER=mysql 设置运行用户 -DDEFAULT_CHARSET=utf8 设置默认字符集,默认latin1 -DEFAULT_COLLATION=utf8_general_ci 设置默认校对规则,默认latin1_general_ci -DWITH_INNOBASE_STORAGE_ENGINE=1 添加InnoDB引擎支持 -DENABLE_DOWNLOADS=1 自动下载可选文件,比如自动下载谷歌的测试包 -DMYSQL_TCP_PORT=3306 设置服务器监听端口,默认3306 -DSYSCONFDIR=/etc 设置my.cnf所在目录,默认为安装目录) 执行过程中会出现: CMake Error: Problem with tar_extract_all(): Invalid argument CMake Error: Problem extracting tar: /usr/local/src/mysql-5.6.26/source_downloads/gmock-1.6.0.zip 解决方法: cd mysql目录下面会发现有一个source_downloads目录,需要解压unzip gmock-1.6.0.zip,然后再重新执行上述配置过程。当然你也可以去掉-DENABLE_DOWNLOADS=1这个选项,不编译谷歌的测试包也没有什么问题,但是之前的某些版本会出现无法编译的问题. 11、cmake结束后开始编译源码,这一步时间会较长,请耐心等待: # make 12、安装编译好的程序: # make install (注意:如果需要重装mysql,在/usr/local/src/mysql-5.6.26在执行下make install就可以了,不需要再cmake和make) 13、清除安装临时文件: # make clean 14、修改mysql目录拥有者为mysql用户: # chown -Rf mysql:mysql /usr/local/mysql # chown -Rf mysql:mysql /home/mysql 15、进入mysql执行程序的安装路径: # cd /usr/local/mysql 16、执行初始化配置脚本,创建系统自带的数据库和表(注意:路径/home/mysql/data需要换成你自定定义的数据库存放路径): # scripts/mysql_install_db --user=mysql --basedir=/usr/local/mysql --datadir=/home/mysql/data Installing MySQL system tables...2015-12-13 15:21:53 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details). 2015-12-13 15:21:53 0 [Note] /usr/local/mysql/bin/mysqld (mysqld 5.6.26) starting as process 17362 ... 2015-12-13 15:21:53 17362 [Note] InnoDB: Using atomics to ref count buffer pool pages 2015-12-13 15:21:53 17362 [Note] InnoDB: The InnoDB memory heap is disabled 2015-12-13 15:21:53 17362 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins 2015-12-13 15:21:53 17362 [Note] InnoDB: Memory barrier is not used 2015-12-13 15:21:53 17362 [Note] InnoDB: Compressed tables use zlib 1.2.3 2015-12-13 15:21:53 17362 [Note] InnoDB: Using CPU crc32 instructions 2015-12-13 15:21:53 17362 [Note] InnoDB: Initializing buffer pool, size = 128.0M 2015-12-13 15:21:53 17362 [Note] InnoDB: Completed initialization of buffer pool 2015-12-13 15:21:53 17362 [Note] InnoDB: The first specified data file ./ibdata1 did not exist: a new database to be created! 2015-12-13 15:21:53 17362 [Note] InnoDB: Setting file ./ibdata1 size to 12 MB 2015-12-13 15:21:53 17362 [Note] InnoDB: Database physically writes the file full: wait... 2015-12-13 15:21:53 17362 [Note] InnoDB: Setting log file ./ib_logfile101 size to 48 MB 2015-12-13 15:21:53 17362 [Note] InnoDB: Setting log file ./ib_logfile1 size to 48 MB 2015-12-13 15:21:53 17362 [Note] InnoDB: Renaming log file ./ib_logfile101 to ./ib_logfile0 2015-12-13 15:21:53 17362 [Warning] InnoDB: New log files created, LSN=45781 2015-12-13 15:21:53 17362 [Note] InnoDB: Doublewrite buffer not found: creating new 2015-12-13 15:21:53 17362 [Note] InnoDB: Doublewrite buffer created 2015-12-13 15:21:53 17362 [Note] InnoDB: 128 rollback segment(s) are active. 2015-12-13 15:21:53 17362 [Warning] InnoDB: Creating foreign key constraint system tables. 2015-12-13 15:21:53 17362 [Note] InnoDB: Foreign key constraint system tables created 2015-12-13 15:21:53 17362 [Note] InnoDB: Creating tablespace and datafile system tables. 2015-12-13 15:21:53 17362 [Note] InnoDB: Tablespace and datafile system tables created. 2015-12-13 15:21:53 17362 [Note] InnoDB: Waiting for purge to start 2015-12-13 15:21:53 17362 [Note] InnoDB: 5.6.26 started; log sequence number 0 2015-12-13 15:21:53 17362 [Note] Binlog end 2015-12-13 15:21:53 17362 [Note] InnoDB: FTS optimize thread exiting. 2015-12-13 15:21:53 17362 [Note] InnoDB: Starting shutdown... 2015-12-13 15:21:54 17362 [Note] InnoDB: Shutdown completed; log sequence number 1625977 OK Filling help tables...2015-12-13 15:21:54 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details). 2015-12-13 15:21:54 0 [Note] /usr/local/mysql/bin/mysqld (mysqld 5.6.26) starting as process 17384 ... 2015-12-13 15:21:54 17384 [Note] InnoDB: Using atomics to ref count buffer pool pages 2015-12-13 15:21:54 17384 [Note] InnoDB: The InnoDB memory heap is disabled 2015-12-13 15:21:54 17384 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins 2015-12-13 15:21:54 17384 [Note] InnoDB: Memory barrier is not used 2015-12-13 15:21:54 17384 [Note] InnoDB: Compressed tables use zlib 1.2.3 2015-12-13 15:21:54 17384 [Note] InnoDB: Using CPU crc32 instructions 2015-12-13 15:21:54 17384 [Note] InnoDB: Initializing buffer pool, size = 128.0M 2015-12-13 15:21:54 17384 [Note] InnoDB: Completed initialization of buffer pool 2015-12-13 15:21:54 17384 [Note] InnoDB: Highest supported file format is Barracuda. 2015-12-13 15:21:54 17384 [Note] InnoDB: 128 rollback segment(s) are active. 2015-12-13 15:21:54 17384 [Note] InnoDB: Waiting for purge to start 2015-12-13 15:21:54 17384 [Note] InnoDB: 5.6.26 started; log sequence number 1625977 2015-12-13 15:21:55 17384 [Note] Binlog end 2015-12-13 15:21:55 17384 [Note] InnoDB: FTS optimize thread exiting. 2015-12-13 15:21:55 17384 [Note] InnoDB: Starting shutdown... 2015-12-13 15:21:56 17384 [Note] InnoDB: Shutdown completed; log sequence number 1625987 OK To start mysqld at boot time you have to copy support-files/mysql.server to the right place for your system PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER ! To do so, start the server, then issue the following commands: /usr/local/mysql/bin/mysqladmin -u root password 'new-password' /usr/local/mysql/bin/mysqladmin -u root -h edu-mysql-02 password 'new-password' Alternatively you can run: /usr/local/mysql/bin/mysql_secure_installation which will also give you the option of removing the test databases and anonymous user created by default. This is strongly recommended for production servers. See the manual for more instructions. You can start the MySQL daemon with: cd . ; /usr/local/mysql/bin/mysqld_safe & You can test the MySQL daemon with mysql-test-run.pl cd mysql-test ; perl mysql-test-run.pl Please report any problems at http://bugs.mysql.com/ The latest information about MySQL is available on the web at http://www.mysql.com Support MySQL by buying support/licenses at http://shop.mysql.com New default config file was created as /usr/local/mysql/my.cnf and will be used by default by the server when you start it. You may edit this file to change server settings WARNING: Default config file /etc/my.cnf exists on the system This file will be read by default by the MySQL server If you do not want to use this, either remove it, or use the --defaults-file argument to mysqld_safe when starting the server 17、初始化脚本在/usr/local/mysql/下生成了配置文件my.cnf,需要更改该配置文件的所有者: # ls -lah [root@edu-mysql-01 mysql] # chown -Rf mysql:mysql /usr/local/mysql/my.cnf 18、注意: (1)Tips:在启动MySQL服务时,会按照一定次序搜索my.cnf,先在/etc目录下找,找不到则会搜索mysql程序目录下是否有my.cnf(2)需要注意CentOS 6版操作系统的最小安装完成后,即使没有安装mysql,在/etc目录下也会存在一个my.cnf文件,建议将此文件更名为其他的名字,否则该文件会干扰源码安装的MySQL的正确配置,造成无法启动。修改/etc/my.cnf操作如下: 可以:mv /etc/my.cnf /etc/my.cnf.bak 也可以:删除掉/etc/my.cnf这个文件:rm /etc/my.cnf 如果你需要用于生产环境,不要急着做下面的mysql启动操作。建议把上一步骤中mysql初始化生成的/usr/local/mysql/my.cnf删除,然后把你优化好的mysql配置文件my.cnf放到/etc下。(这是做mysql主从复制和mysql优化的经验!) (我们这里使用/etc/my.cnf) 19、编辑/etc/my.cnf: # vi /etc/my.cnf [client] port = 3306 socket = /usr/local/mysql/mysql.sock [mysqld] character-set-server = utf8 collation-server = utf8_general_ci skip-external-locking skip-name-resolve user = mysql port = 3306 basedir = /usr/local/mysql datadir = /home/mysql/data tmpdir = /home/mysql/temp # server_id = ..... socket = /usr/local/mysql/mysql.sock log-error = /home/mysql/logs/mysql_error.log pid-file = /home/mysql/mysql.pid open_files_limit = 10240 back_log = 600 max_connections=500 max_connect_errors = 6000 wait_timeout=605800 #open_tables = 600 #table_cache = 650 #opened_tables = 630 max_allowed_packet = 32M sort_buffer_size = 4M join_buffer_size = 4M thread_cache_size = 300 query_cache_type = 1 query_cache_size = 256M query_cache_limit = 2M query_cache_min_res_unit = 16k tmp_table_size = 256M max_heap_table_size = 256M key_buffer_size = 256M read_buffer_size = 1M read_rnd_buffer_size = 16M bulk_insert_buffer_size = 64M lower_case_table_names=1 default-storage-engine = INNODB innodb_buffer_pool_size = 2G innodb_log_buffer_size = 32M innodb_log_file_size = 128M innodb_flush_method = O_DIRECT ##################### thread_concurrency = 32 long_query_time= 2 slow-query-log = on slow-query-log-file = /home/mysql/logs/mysql-slow.log [mysqldump] quick max_allowed_packet = 32M [mysqld_safe] log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid 20、复制服务启动脚本: # cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysql 21、启动MySQL服务: # service mysql start Starting MySQL.. SUCCESS! (初次启动会在/usr/local/mysql目录下生成mysql.sock文件) 22、设置MySQL开机自动启动服务: # chkconfig mysql on 设置MySQL数据库root用户的本地登录密码(初始用户没有密码): # mysqladmin -u root password 'roncoo' 23、登录并修改MySQL用户root的密码: # mysql -uroot -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 Server version: 5.6.26-log Source distribution Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | test | +--------------------+ 4 rows in set (0.00 sec) mysql> use mysql; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A 修改root用户密码: mysql> update user set Password = password('roncoo.com') where User='root'; Query OK, 4 rows affected (0.00 sec) Rows matched: 5 Changed: 4 Warnings: 0 mysql> flush privileges; Query OK, 0 rows affected (0.00 sec) 允许root远程登录,设置远程登录密码:www.roncoo.com mysql> use mysql; mysql>GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'www.roncoo.com' WITH GRANT OPTION; mysql> flush privileges; mysql> exit; 注意:真实生产环境,应用操作不要使用root用户。 重新登录 [root@edu-mysql-01 ~]# mysql -uroot -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 9 Server version: 5.6.26-log Source distribution Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> 24、运行安全设置脚本,强烈建议生产服务器使用(可选): [root@edu-mysql-01 ~]# /usr/local/mysql/bin/mysql_secure_installation NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MySQL SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY! In order to log into MySQL to secure it, we'll need the current password for the root user. If you've just installed MySQL, and you haven't set the root password yet, the password will be blank, so you should just press enter here. Enter current password for root (enter for none): ----->此处输入root密码 OK, successfully used password, moving on... Setting the root password ensures that nobody can log into the MySQL root user without the proper authorisation. You already have a root password set, so you can safely answer 'n'. Change the root password? [Y/n] n -----> 上已为root设置了密码,此处可输n ... skipping. By default, a MySQL installation has an anonymous user, allowing anyone to log into MySQL without having to have a user account created for them. This is intended only for testing, and to make the installation go a bit smoother. You should remove them before moving into a production environment. Remove anonymous users? [Y/n] Y ------> 删除匿名用户 ... Success! Normally, root should only be allowed to connect from 'localhost'. This ensures that someone cannot guess at the root password from the network. Disallow root login remotely? [Y/n] n -----> 一般不允许root远程登录,可添加普通用户,然后设置允许远程登录 ... skipping. By default, MySQL comes with a database named 'test' that anyone can access. This is also intended only for testing, and should be removed before moving into a production environment. Remove test database and access to it? [Y/n] Y -----> 删除test库及相应权限 - Dropping test database... ... Success! - Removing privileges on test database... ... Success! Reloading the privilege tables will ensure that all changes made so far will take effect immediately. Reload privilege tables now? [Y/n] Y -----> 重新加载权限表使设置生效 ... Success! All done! If you've completed all of the above steps, your MySQL installation should now be secure. Thanks for using MySQL! Cleaning up... 25、重启服务器,检测mysql是否能开机自动启动: [root@edu-mysql-01 ~] # reboot 参考内容:基于Dubbo的分布式系统架构项目实战
Dubbo官方文档:用户指南 >> 示例 >> 直连提供者注意点:1、 直连提供者只需要在消费端设置2、 ${user.home}指的是当前操作系统用户目录,如Win7系统Administrator的用户目录就是C:UsersAdministrator 视频资源:http://www.roncoo.com/course/view/85d6008fe77c4199b0cdd2885eaeee53
Dubbo官方文档:用户指南 >> 示例 >> 线程模型 配置标签: <dubbo:provider/> <dubbo:protocol/> 实战经验分享(属用性能调优):Linux用户线程数限制导致的java.lang.OutOfMemoryError: unable to create new native thread 异常 # vi /etc/security/limits.d/90-nproc.conf # Default limit for number of user's processes to prevent # accidental fork bombs. # See rhbz #432903 for reasoning. root soft nproc unlimited * soft nproc 20480 调整时要注意:1、 尽量不要使用root用户来部署应用程序,避免资源耗尽后无法登录操作系统。2、 普通用户的线程数限制值要看可用物理内存容量来配置 计算方式:default_nproc = total_memory/128K; $ cat /proc/meminfo |grep MemTotal$ echo "5993104 / 128"| bc$ ulimit -u ulimit -a # 显示目前资源限制的设定ulimit -u # 用户最多可开启的程序数目 重启,使之生效:# reboot 参考:http://www.roncoo.com/course/view/85d6008fe77c4199b0cdd2885eaeee53
参考内容:http://www.roncoo.com/course/view/85d6008fe77c4199b0cdd2885eaeee53 负载均衡(+) (#) 在集群负载均衡时,Dubbo提供了多种均衡策略,缺省为random随机调用。 可以自行扩展负载均衡策略,参见:负载均衡扩展 Random LoadBalance随机,按权重设置随机概率。在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。 权重加倍 RoundRobin LoadBalance 轮循,按公约后的权重设置轮循比率。 存在慢的提供者累积请求问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。 解决办法 :结合权重,把第二台机(性能低的)的权重设置低一点 LeastActive LoadBalance 最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。 使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。 ConsistentHash LoadBalance 一致性Hash,相同参数的请求总是发到同一提供者。 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。 算法参见:http://en.wikipedia.org/wiki/Consistent_hashing。 缺省只对第一个参数Hash,如果要修改,请配置<dubbo:parameter key="hash.arguments" value="0,1" /> 缺省用160份虚拟节点,如果要修改,请配置<dubbo:parameter key="hash.nodes" value="320" /> Dubbo管理台配置负载均衡 权重调节 配置如: <dubbo:serviceinterface="..."loadbalance="roundrobin"/> 或: <dubbo:referenceinterface="..."loadbalance="roundrobin"/> 或: <dubbo:serviceinterface="..."> <dubbo:methodname="..."loadbalance="roundrobin"/> </dubbo:service> 一般在实际项目我们配置权重或负载均衡时不在代码中写死,我们动态使用默认配置,需要调节时通过dubbo管控台上进行配置 或: <dubbo:referenceinterface="..."> <dubbo:methodname="..."loadbalance="roundrobin"/> </dubbo:reference>
Dubbo官方文档:用户指南 >> 示例 >> 启动时检查 资源:http://www.roncoo.com/course/view/85d6008fe77c4199b0cdd2885eaeee53
一、前期准备 1、MySQL数据库的安装:MySQL-5.6.22,自行安装 2、Dubbo视频教程--基础篇--第03节--ZooKeeper注册中心安装 3、Dubbo视频教程--基础篇--第06节--Dubbo管理控制台的安装 4、Dubbo视频教程--基础篇--第10节--Dubbo监控中心的介绍与简易监控中心的安装 5、持续集成管理平台(SVN、Nexus、Maven、Hudson)的安装: Dubbo视频教程--基础篇--第11节至18节 6、Dubbo视频教程--高级篇--第21节--ActiveMQ的安装与使用 7、Dubbo视频教程--高级篇--第22节--Redis的安装与使用 8、Dubbo视频教程--高级篇--第23节--FastDFS分布式文件系统的安装与使用 二、对部署环境进行规划 创建数据库 数据库编码为:UTF-8 数据库引擎为:InnoDB 导入“基于Dubbo的分布式系统架构视频教程--简易版支付系统源码.rar”中的 “数据库--edu_simple_pay.rar”中的“edu_simple_pay.sql” 调整公共配置文件 应用部署前期准备 1、common工程构建、发布到Maven私有库 尤其注意pay-common-config工程的构建(配置文件修改后需要重新构建,引用处也要重新构建) 2、facade工程构建、发布到Maven私有库 部署服务 1、规划好服务部署目录,准备好服务管理脚本 /home/wusc/edu/service/account/service-account.sh #!/bin/sh ## java env export JAVA_HOME=/usr/local/java/jdk1.7.0_72 export JRE_HOME=$JAVA_HOME/jre ## you just need to change this param name APP_NAME=account SERVICE_DIR=/home/wusc/edu/service/$APP_NAME SERVICE_NAME=pay-service-$APP_NAME JAR_NAME=$SERVICE_NAME\.jar PID=$SERVICE_NAME\.pid cd $SERVICE_DIR case "$1" in start) nohup $JRE_HOME/bin/java -Xms128m -Xmx512m -jar $JAR_NAME >/dev/null 2>&1 & echo $! > $SERVICE_DIR/$PID echo "=== start $SERVICE_NAME" ;; stop) kill `cat $SERVICE_DIR/$PID` rm -rf $SERVICE_DIR/$PID echo "=== stop $SERVICE_NAME" sleep 5 P_ID=`ps -ef | grep -w "$SERVICE_NAME" | grep -v "grep" | awk '{print $2}'` if [ "$P_ID" == "" ]; then echo "=== $SERVICE_NAME process not exists or stop success" else echo "=== $SERVICE_NAME process pid is:$P_ID" echo "=== begin kill $SERVICE_NAME process, pid is:$P_ID" kill -9 $P_ID fi ;; restart) $0 stop sleep 2 $0 start echo "=== restart $SERVICE_NAME" ;; *) ## restart $0 stop sleep 2 $0 start ;; esac exit 0 2、使用Hudson来自动化部署服务 3、通过Dubbo管控台检查各服务是否都部署成功 部署Web应用 1、规划好Web应用部署目录、端口、脚本 bank-receive-tomcat 8081 boss-tomcat 8082 gateway-tomcat 8083 notify-receive-tomcat 8084 portal-tomcat 8085 shop-tomcat 8086 trade-tomcat 8087 /home/wusc/edu/web/bank-receive-tomcat/restart.sh ## java env export JAVA_HOME=/usr/local/java/jdk1.7.0_72 export JRE_HOME=$JAVA_HOME/jre ## restart tomcat current_dir=$(cd `dirname $0`; pwd) echo "=== current_dir is:$current_dir" $current_dir/bin/shutdown.sh sleep 3 rm -rf $current_dir/webapps/*/ sleep 2 $current_dir/bin/startup.sh 部署APP /home/wusc/edu/app/queue-notify/app-queue-notify.sh #!/bin/sh ## java env export JAVA_HOME=/usr/local/java/jdk1.7.0_72 export JRE_HOME=$JAVA_HOME/jre ## you only need to change next two parameters value APP_DIR=/home/wusc/edu/app/queue-notify APP_NAME=pay-app-queue-notify JAR_NAME=$APP_NAME\.jar cd $APP_DIR ## check app process weather exists process=`ps aux | grep -w "$APP_NAME" | grep -v grep` if [ "$process" == "" ]; then echo "=== $APP_NAME process not exists" else echo "=== $APP_NAME process exists" echo "=== $APP_NAME process is : $process" ## get PID by process name P_ID=`ps -ef | grep -w "$APP_NAME" | grep -v "grep" | awk '{print $2}'` echo "=== $APP_NAME process PID is:$P_ID" echo "=== begin kill $APP_NAME process" kill $P_ID sleep 3 P_ID=`ps -ef | grep -w "$APP_NAME" | grep -v "grep" | awk '{print $2}'` if [ "$P_ID" == "" ]; then echo "=== $APP_NAME process stop success" else echo "=== $APP_NAME process kill failed, PID is:$P_ID" echo "=== begin kill -9 $APP_NAME process, PID is:$P_ID" sleep 3 kill -9 $P_ID fi fi sleep 2 echo "=== begin start $APP_NAME" $JRE_HOME/bin/java -Xms128m -Xmx512m -jar $APP_DIR/$JAR_NAME >/dev/null 2>&1 & 部署定时任务 定时任务的部署与调用分离 /home/wusc/edu/timer/report/timer-report.sh #!/bin/sh ## java env export JAVA_HOME=/usr/local/java/jdk1.7.0_72 export JRE_HOME=$JAVA_HOME/jre ## you only need to chage next two line value SERVICE_DIR=/home/wusc/edu/timer/report APP_NAME=pay-timer-report JAR_NAME=$APP_NAME\.jar sleep 1 echo "=== invoke task, please wait" $JRE_HOME/bin/java -jar $SERVICE_DIR/$JAR_NAME >/dev/null 2>&1 & ## until process stop to print log while true do process=`ps aux | grep $APP_NAME | grep -v grep`; if [ "$process" == "" ]; then sleep 1; echo "=== task complete"; sleep 3; break; else echo "=== process is running, please wait"; sleep 10; continue; fi done
一、工程结构pay-common-parent 项目的Maven父配置工程pay-common 公共工程,所有项目均可引用pay-common-config 公共配置工程pay-common-core 公共核心工程,service工程共用pay-common-web 公共web工程,web工程共用 pay-api-merchant 商户API工程,商户对接支付平台时使用(如:模拟商城pay-web-shop) pay-facade-account 账户服务接口pay-facade-bank 银行管理服务接口pay-facade-banklink 银行后置服务接口pay-facade-boss 运营服务接口pay-facade-cost 成本计算服务接口pay-facade-fee 商户计费服务接口pay-facade-limit 交易限制服务接口pay-facade-notify 通知服务接口pay-facade-payrule 支付规则服务接口pay-facade-remit 打款服务接口pay-facade-report 报表服务接口pay-facade-settlement 结算服务接口pay-facade-trade 交易服务接口pay-facade-user 用户服务接口 pay-service-account 账户服务pay-service-bank 银行管理服务pay-service-banklink 银行后置服务pay-service-boss 运营服务pay-service-cost 成本计算服务pay-service-fee 商户计费服务pay-service-limit 交易限制服务pay-service-notify 通知服务pay-service-payrule 支付规则服务pay-service-remit 打款服务pay-service-report 报表服务pay-service-settlement 结算服务pay-service-trade 交易服务pay-service-user 用户服务 pay-app-queue-notify 消息队列监听APP pay-timer-report 报表分析定时任务 pay-web-bank-receive 银行回调请求信息接收pay-web-boss 运营管理系统pay-web-gateway 支付网关pay-web-notify-receive 通知消息接收pay-web-portal 门户系统pay-web-trade 交易接口 pay-web-shop 模拟商城 二、系统简要功能演示 三、技术点介绍FastDFS分布式文件系统的使用ActiveMQ消息队列的使用Redis分布式缓存的使用 四、部署结构介绍 部署视频教程参考:http://www.roncoo.com/course/view/85d6008fe77c4199b0cdd2885eaeee53
跟踪服务器:192.168.4.121 (edu-dfs-tracker-01) 存储服务器:192.168.4.125 (edu-dfs-storage-01) 环境:CentOS 6.6 用户:root 数据目录:/fastdfs (注:数据目录按你的数据盘挂载路径而定) 安装包: FastDFS v5.05 libfastcommon-master.zip(是从FastDFS和FastDHT中提取出来的公共C函数库) fastdfs-nginx-module_v1.16.tar.gz nginx-1.6.2.tar.gz fastdfs_client_java._v1.25.tar.gz 源码地址:https://github.com/happyfish100/ 下载地址:http://sourceforge.net/projects/fastdfs/files/ 官方论坛:http://bbs.chinaunix.net/forum-240-1.html 一、所有跟踪服务器和存储服务器均执行如下操作 1、编译和安装所需的依赖包: # yum install make cmake gcc gcc-c++ 2、安装libfastcommon: (1)上传或下载libfastcommon-master.zip到/usr/local/src目录 (2)解压 # cd /usr/local/src/ # unzip libfastcommon-master.zip # cd libfastcommon-master (3) 编译、安装 # ./make.sh # ./make.sh install libfastcommon默认安装到了 /usr/lib64/libfastcommon.so /usr/lib64/libfdfsclient.so (4)因为FastDFS主程序设置的lib目录是/usr/local/lib,所以需要创建软链接. # ln -s /usr/lib64/libfastcommon.so /usr/local/lib/libfastcommon.so # ln -s /usr/lib64/libfastcommon.so /usr/lib/libfastcommon.so # ln -s /usr/lib64/libfdfsclient.so /usr/local/lib/libfdfsclient.so # ln -s /usr/lib64/libfdfsclient.so /usr/lib/libfdfsclient.so 3、安装FastDFS (1)上传或下载FastDFS源码包(FastDFS_v5.05.tar.gz)到 /usr/local/src 目录 (2)解压 # cd /usr/local/src/ # tar -zxvf FastDFS_v5.05.tar.gz # cd FastDFS (3)编译、安装(编译前要确保已经成功安装了libfastcommon) # ./make.sh # ./make.sh install 采用默认安装的方式安装,安装后的相应文件与目录: A、服务脚本在: /etc/init.d/fdfs_storaged /etc/init.d/fdfs_tracker B、配置文件在(样例配置文件): /etc/fdfs/client.conf.sample /etc/fdfs/storage.conf.sample /etc/fdfs/tracker.conf.sample C、命令工具在/usr/bin/目录下的: fdfs_appender_test fdfs_appender_test1 fdfs_append_file fdfs_crc32 fdfs_delete_file fdfs_download_file fdfs_file_info fdfs_monitor fdfs_storaged fdfs_test fdfs_test1 fdfs_trackerd fdfs_upload_appender fdfs_upload_file stop.sh restart.sh (4)因为FastDFS服务脚本设置的bin目录是/usr/local/bin,但实际命令安装在/usr/bin,可以进入 /user/bin目录使用以下命令查看fdfs的相关命令: # cd /usr/bin/ # ls | grep fdfs 因此需要修改FastDFS服务脚本中相应的命令路径,也就是把/etc/init.d/fdfs_storaged 和/etc/init.d/fdfs_tracker两个脚本中的/usr/local/bin修改成/usr/bin: # vi fdfs_trackerd 使用查找替换命令进统一修改:%s+/usr/local/bin+/usr/bin # vi fdfs_storaged 使用查找替换命令进统一修改:%s+/usr/local/bin+/usr/bin 二、配置FastDFS跟踪器(192.168.4.121) 1、 复制FastDFS跟踪器样例配置文件,并重命名: # cd /etc/fdfs/ # cp tracker.conf.sample tracker.conf 2、 编辑跟踪器配置文件: # vi /etc/fdfs/tracker.conf 修改的内容如下: disabled=false port=22122 base_path=/fastdfs/tracker (其它参数保留默认配置,具体配置解释请参考官方文档说明: http://bbs.chinaunix.net/thread-1941456-1-1.html ) 3、 创建基础数据目录(参考基础目录base_path配置): # mkdir -p /fastdfs/tracker 4、 防火墙中打开跟踪器端口(默认为22122): # vi /etc/sysconfig/iptables 添加如下端口行: -A INPUT -m state --state NEW -m tcp -p tcp --dport 22122 -j ACCEPT 重启防火墙: # service iptables restart 5、 启动Tracker: # /etc/init.d/fdfs_trackerd start (初次成功启动,会在/fastdfs/tracker目录下创建data、logs两个目录) 查看FastDFS Tracker是否已成功启动: # ps -ef | grep fdfs 6、 关闭Tracker: # /etc/init.d/fdfs_trackerd stop 7、 设置FastDFS跟踪器开机启动: # vi /etc/rc.d/rc.local 添加以下内容: ## FastDFS Tracker /etc/init.d/fdfs_trackerd start 三、配置FastDFS存储(192.168.4.125) 1、 复制FastDFS存储器样例配置文件,并重命名: # cd /etc/fdfs/ # cp storage.conf.sample storage.conf 2、 编辑存储器样例配置文件: # vi /etc/fdfs/storage.conf 修改的内容如下: disabled=false port=23000 base_path=/fastdfs/storage store_path0=/fastdfs/storage tracker_server=192.168.4.121:22122 http.server_port=8888 (其它参数保留默认配置,具体配置解释请参考官方文档说明: http://bbs.chinaunix.net/thread-1941456-1-1.html ) 3、 创建基础数据目录(参考基础目录base_path配置): # mkdir -p /fastdfs/storage 4、 防火墙中打开存储器端口(默认为23000): # vi /etc/sysconfig/iptables 添加如下端口行: -A INPUT -m state --state NEW -m tcp -p tcp --dport 23000 -j ACCEPT 重启防火墙: # service iptables restart 5、 启动Storage: # /etc/init.d/fdfs_storaged start (初次成功启动,会在/fastdfs/storage目录下创建data、logs两个目录) 查看FastDFS Storage是否已成功启动 # ps -ef | grep fdfs 6、 关闭Storage: # /etc/init.d/fdfs_storaged stop 7、 设置FastDFS存储器开机启动: # vi /etc/rc.d/rc.local 添加: ## FastDFS Storage /etc/init.d/fdfs_storaged start 四、文件上传测试(192.168.4.121) 1、修改Tracker服务器中的客户端配置文件: # cp /etc/fdfs/client.conf.sample /etc/fdfs/client.conf # vi /etc/fdfs/client.conf base_path=/fastdfs/tracker tracker_server=192.168.4.121:22122 2、执行如下文件上传命令: # /usr/bin/fdfs_upload_file /etc/fdfs/client.conf /usr/local/src/FastDFS_v5.05.tar.gz 返回ID号:group1/M00/00/00/wKgEfVUYNYeAb7XFAAVFOL7FJU4.tar.gz (能返回以上文件ID,说明文件上传成功) 五、在每个存储节点上安装nginx 1、fastdfs-nginx-module作用说明 FastDFS通过Tracker服务器,将文件放在Storage服务器存储,但是同组存储服务器之间需要进入文件复制,有同步延迟的问题。假设Tracker服务器将文件上传到了192.168.4.125,上传成功后文件ID已经返回给客户端。此时FastDFS存储集群机制会将这个文件同步到同组存储192.168.4.126,在文件还没有复制完成的情况下,客户端如果用这个文件ID在192.168.4.126上取文件,就会出现文件无法访问的错误。而fastdfs-nginx-module可以重定向文件连接到源服务器取文件,避免客户端由于复制延迟导致的文件无法访问错误。(解压后的fastdfs-nginx-module在nginx安装时使用) 2、上传fastdfs-nginx-module_v1.16.tar.gz到/usr/local/src 3、解压 # cd /usr/local/src/ # tar -zxvf fastdfs-nginx-module_v1.16.tar.gz 4、修改fastdfs-nginx-module的config配置文件 # cd fastdfs-nginx-module/src # vi config CORE_INCS="$CORE_INCS /usr/local/include/fastdfs /usr/local/include/fastcommon/" 修改为: CORE_INCS="$CORE_INCS /usr/include/fastdfs /usr/include/fastcommon/" (注意:这个路径修改是很重要的,不然在nginx编译的时候会报错的) 5、上传当前的稳定版本Nginx(nginx-1.6.2.tar.gz)到/usr/local/src目录 6、安装编译Nginx所需的依赖包 # yum install gcc gcc-c++ make automake autoconf libtool pcre* zlib openssl openssl-devel 7、编译安装Nginx(添加fastdfs-nginx-module模块) # cd /usr/local/src/ # tar -zxvf nginx-1.6.2.tar.gz # cd nginx-1.6.2 # ./configure --add-module=/usr/local/src/fastdfs-nginx-module/src # make && make install 8、复制fastdfs-nginx-module源码中的配置文件到/etc/fdfs目录,并修改 # cp /usr/local/src/fastdfs-nginx-module/src/mod_fastdfs.conf /etc/fdfs/ # vi /etc/fdfs/mod_fastdfs.conf 修改以下配置: connect_timeout=10 base_path=/tmp tracker_server=192.168.4.121:22122 storage_server_port=23000 group_name=group1 url_have_group_name = true store_path0=/fastdfs/storage 9、复制FastDFS的部分配置文件到/etc/fdfs目录 # cd /usr/local/src/FastDFS/conf # cp http.conf mime.types /etc/fdfs/ 10、在/fastdfs/storage文件存储目录下创建软连接,将其链接到实际存放数据的目录 # ln -s /fastdfs/storage/data/ /fastdfs/storage/data/M00 11、配置Nginx 简洁版nginx配置样例: user root; worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 8888; server_name localhost; location ~/group([0-9])/M00 { #alias /fastdfs/storage/data; ngx_fastdfs_module; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } } 注意、说明: A、8888端口值是要与/etc/fdfs/storage.conf中的http.server_port=8888 相对应, 因为http.server_port默认为8888,如果想改成80,则要对应修改过来。 B、Storage对应有多个group的情况下,访问路径带group名,如/group1/M00/00/00/xxx, 对应的Nginx配置为: location ~/group([0-9])/M00 { ngx_fastdfs_module; } C、如查下载时如发现老报404,将nginx.conf第一行user nobody修改为user root后重新启动。 12、防火墙中打开Nginx的8888端口 # vi /etc/sysconfig/iptables 添加: -A INPUT -m state --state NEW -m tcp -p tcp --dport 8888 -j ACCEPT # service iptables restart 13、启动Nginx # /usr/local/nginx/sbin/nginx ngx_http_fastdfs_set pid=xxx (重启Nginx的命令为:/usr/local/nginx/sbin/nginx -s reload) 14、通过浏览器访问测试时上传的文件基于Dubbo的分布式系统架构实战 http://192.168.4.125:8888/group1/M00/00/00/wKgEfVUYNYeAb7XFAAVFOL7FJU4.tar.gz 六、FastDFS的使用的Demo样例讲解与演示: 具体内容请参考样例代码和视频教程 注意:千万不要使用kill -9命令强杀FastDFS进程,否则可能会导致binlog数据丢失。
IP:192.168.4.111 环境:CentOS 6.6 Redis版本:redis-3.0 (考虑到Redis3.0在集群和性能提升方面的特性,rc版为正式版的候选版,而且很快就出正式版) 安装目录:/usr/local/redis 用户:root 编译和安装所需的包: # yum install gcc tcl 下载3.0版Redis(当前最新版redis-3.0.0-rc5.tar.gz,请学员们在安装时自行选用最新版) # cd /usr/local/src # wget https://github.com/antirez/redis/archive/3.0.0-rc5.tar.gz 创建安装目录: # mkdir /usr/local/redis 解压: # tar -zxvf 3.0.0-rc5.tar.gz # mv redis-3.0.0-rc5 redis3.0 # cd redis3.0 安装(使用PREFIX指定安装目录): # make PREFIX=/usr/local/redis install 安装完成后,可以看到/usr/local/redis目录下有一个bin目录,bin目录里就是redis的命令脚本: redis-benchmark redis-check-aof redis-check-dump redis-cli redis-server 将Redis配置成服务: 按上面的操作步骤,Redis的启动脚本为:/usr/local/src/redis3.0/utils/redis_init_script 将启动脚本复制到/etc/rc.d/init.d/目录下,并命名为redis: # cp /usr/local/src/redis3.0/utils/redis_init_script /etc/rc.d/init.d/redis 编辑/etc/rc.d/init.d/redis,修改相应配置,使之能注册成为服务: # vi /etc/rc.d/init.d/redis #!/bin/sh # # Simple Redis init.d script conceived to work on Linux systems # as it does use of the /proc filesystem. REDISPORT=6379 EXEC=/usr/local/bin/redis-server CLIEXEC=/usr/local/bin/redis-cli PIDFILE=/var/run/redis_${REDISPORT}.pid CONF="/etc/redis/${REDISPORT}.conf" case "$1" in start) if [ -f $PIDFILE ] then echo "$PIDFILE exists, process is already running or crashed" else echo "Starting Redis server..." $EXEC $CONF fi ;; stop) if [ ! -f $PIDFILE ] then echo "$PIDFILE does not exist, process is not running" else PID=$(cat $PIDFILE) echo "Stopping ..." $CLIEXEC -p $REDISPORT shutdown while [ -x /proc/${PID} ] do echo "Waiting for Redis to shutdown ..." sleep 1 done echo "Redis stopped" fi ;; *) echo "Please use start or stop as first argument" ;; esac 查看以上redis服务脚本,关注标为橙色的几个属性,做如下几个修改的准备: (1) 在脚本的第一行后面添加一行内容如下: #chkconfig: 2345 80 90 (如果不添加上面的内容,在注册服务时会提示:service redis does not support chkconfig) (2) REDISPORT端口保持6379不变;(注意,端口名将与下面的配置文件名有关) (3) EXEC=/usr/local/bin/redis-server改为 EXEC=/usr/local/redis/bin/redis-server (4) CLIEXEC=/usr/local/bin/redis-cli 改为CLIEXEC=/usr/local/redis/bin/redis-cli (5) 配置文件设置: 创建redis配置文件目录 # mkdir /usr/local/redis/conf 复制redis配置文件/usr/local/src/redis3.0/redis.conf到/usr/local/redis/conf目录并按端口号重命名为6379.conf # cp /usr/local/src/redis3.0/redis.conf /usr/local/redis/conf/6379.conf 做了以上准备后,再对CONF属性作如下调整: CONF="/etc/redis/${REDISPORT}.conf" 改为 CONF="/usr/local/redis/conf/${REDISPORT}.conf" (6) 更改redis开启的命令,以后台运行的方式执行: $EXEC $CONF & #“&”作用是将服务转到后面运行 修改后的/etc/rc.d/init.d/redis服务脚本内容为: #!/bin/sh #chkconfig: 2345 80 90 # # Simple Redis init.d script conceived to work on Linux systems # as it does use of the /proc filesystem. REDISPORT=6379 EXEC=/usr/local/redis/bin/redis-server CLIEXEC=/usr/local/redis/bin/redis-cli PIDFILE=/var/run/redis_${REDISPORT}.pid CONF="/usr/local/redis/conf/${REDISPORT}.conf" case "$1" in start) if [ -f $PIDFILE ] then echo "$PIDFILE exists, process is already running or crashed" else echo "Starting Redis server..." $EXEC $CONF & fi ;; stop) if [ ! -f $PIDFILE ] then echo "$PIDFILE does not exist, process is not running" else PID=$(cat $PIDFILE) echo "Stopping ..." $CLIEXEC -p $REDISPORT shutdown while [ -x /proc/${PID} ] do echo "Waiting for Redis to shutdown ..." sleep 1 done echo "Redis stopped" fi ;; *) echo "Please use start or stop as first argument" ;; esac 以上配置操作完成后,便可将Redis注册成为服务: # chkconfig --add redis 防火墙中打开对应的端口 # vi /etc/sysconfig/iptables 添加: -A INPUT -m state --state NEW -m tcp -p tcp --dport 6379 -j ACCEPT 重启防火墙: # service iptables restart 修改redis配置文件设置: # vi /usr/local/redis/conf/6379.conf 修改如下配置 daemonize no 改为> daemonize yes pidfile /var/run/redis.pid 改为> pidfile /var/run/redis_6379.pid 启动Redis服务 # service redis start 将Redis添加到环境变量中: # vi /etc/profile 在最后添加以下内容: ## Redis env export PATH=$PATH:/usr/local/redis/bin 使配置生效: # source /etc/profile 现在就可以直接使用redis-cli等redis命令了: 关闭Redis服务 # service redis stop 默认情况下,Redis开启安全认证,可以通过/usr/local/redis/conf/6379.conf的requirepass指定一个验证密码。 Redis的使用的Demo样例讲解与演示: 具体内容请参考样例代码和视频教程
IP:192.168.4.101 环境:CentOS 6.6、JDK7 1、 安装JDK并配置环境变量(略) JAVA_HOME=/usr/local/java/jdk1.7.0_72 2、 下载Linux版的ActiveMQ(当前最新版apache-activemq-5.11.1-bin.tar.gz) $ wget http://apache.fayea.com/activemq/5.11.1/apache-activemq-5.11.1-bin.tar.gz 3、 解压安装 $ tar -zxvf apache-activemq-5.11.1-bin.tar.gz $ mv apache-activemq-5.11.1 activemq-01 如果启动脚本activemq没有可执行权限,此时则需要授权(此步可选) $ cd /home/wusc/activemq-01/bin/ $ chmod 755 ./activemq 4、 防火墙中打开对应的端口 ActiveMQ需要用到两个端口 一个是消息通讯的端口(默认为61616) 一个是管理控制台端口(默认为8161)可在conf/jetty.xml中修改,如下: <bean id="jettyPort" class="org.apache.activemq.web.WebConsolePort" init-method="start"> <!-- the default port number for the web console --> <property name="host" value="0.0.0.0"/> <property name="port" value="8161"/> </bean> # vi /etc/sysconfig/iptables 添加: -A INPUT -m state --state NEW -m tcp -p tcp --dport 61616 -j ACCEPT -A INPUT -m state --state NEW -m tcp -p tcp --dport 8161 -j ACCEPT 重启防火墙: # service iptables restart 5、 启动 $ cd /home/wusc/activemq-01/bin $ ./activemq start 6、 打开管理界面:http://192.168.4.101:8161 默认用户名和密码为:admin/admin 登录后进入 7、 安全配置(消息安全) ActiveMQ如果不加入安全机制的话,任何人只要知道消息服务的具体地址(包括ip,端口,消息地址[队列或者主题地址],),都可以肆无忌惮的发送、接收消息。关于ActiveMQ安装配置http://activemq.apache.org/security.html ActiveMQ的消息安全配置策略有多种,我们以简单授权配置为例: 在conf/activemq.xml文件中在broker标签最后加入以下内容即可: $ vi /home/wusc/activemq-01/conf/activemq.xml <plugins> <simpleAuthenticationPlugin> <users> <authenticationUser username="wusc" password="wusc.123" groups="users,admins"/> </users> </simpleAuthenticationPlugin> </plugins> 定义了一个wusc用户,密码为wusc.123,角色为users,admins 设置admin的用户名和密码: $ vi /home/wusc/activemq-01/conf/jetty.xml <bean id="securityConstraint" class="org.eclipse.jetty.util.security.Constraint"> <property name="name" value="BASIC" /> <property name="roles" value="admin" /> <property name="authenticate" value="true" /> </bean> 确保authenticate的值为true(默认) 控制台的登录用户名密码保存在conf/jetty-realm.properties文件中,内容如下: $ vi /home/wusc/activemq-01/conf/jetty-realm.properties # Defines users that can access the web (console, demo, etc.) # username: password [,rolename ...] admin: wusc.123, admin 注意:用户名和密码的格式是 用户名 : 密码 ,角色名 重启: $ /home/wusc/activemq-01/bin/activemq restart 设置开机启动: # vi /etc/rc.local 加入以下内容 ## ActiveMQ su - wusc -c '/home/wusc/activemq-01/bin/activemq start' 8、 MQ消息生产者也与消息消费者的Demo样例讲解与演示 参考内容>>http://www.roncoo.com/course/view/85d6008fe77c4199b0cdd2885eaeee53
IP:192.168.4.221 8G内存(Hudson多个工程在同时构建的情况下比较耗内存) 环境:CentOS 6.6、JDK7 Hudson不需要用到数据库 Hudson只是一个持续集成服务器(持续集成工具),要想搭建一套完整的持续集成管理平台,还需要用到前面课程中所讲到的SVN、Maven、Sonar等工具,按需求整合则可。 1、 安装JDK并配置环境变量(略) JAVA_HOME=/usr/local/java/jdk1.7.0_72 2、 Maven本地仓库的安装(使用Maven作为项目构建与管理工具): (1)下载maven-3.0.5 (注意:建议不要下载3.1或更高版本的Maven,因为与Hudson进行集成时会有问题,之前有遇到过): wget http://mirrors.hust.edu.cn/apache/maven/maven-3/3.0.5/binaries/apache-maven-3.0.5-bin.tar.gz (2)解压: tar -zxvf apache-maven-3.0.5-bin.tar.gz mv apache-maven-3.0.5 maven-3.0.5 (3)配置Maven环境变量: vi /etc/profile maven env export MAVEN_HOME=/root/maven-3.0.5 export PATH=$PATH:$MAVEN_HOME/bin source /etc/profile (4)Maven本地库配置: <?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> <localRepository>/root/maven-3.0.5/.m2/repository</localRepository> <interactiveMode>true</interactiveMode> <offline>false</offline> <pluginGroups> <pluginGroup>org.mortbay.jetty</pluginGroup> <pluginGroup>org.jenkins-ci.tools</pluginGroup> </pluginGroups> <!--配置权限,使用默认用户--> <servers> <server> <id>nexus-releases</id> <username>deployment</username> <password>deployment123</password> </server> <server> <id>nexus-snapshots</id> <username>deployment</username> <password>deployment123</password> </server> </servers> <mirrors> </mirrors> <profiles> <profile> <id>edu</id> <activation> <activeByDefault>false</activeByDefault> <jdk>1.6</jdk> </activation> <repositories> <!-- 私有库地址--> <repository> <id>nexus</id> <url>http://localhost:8081/nexus/content/groups/public/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <!--插件库地址--> <pluginRepository> <id>nexus</id> <url>http://localhost:8081/nexus/content/groups/public/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> </pluginRepositories> </profile> <profile> <id>sonar</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <!-- Example for MySQL--> <sonar.jdbc.url> jdbc:mysql://localhost:3306/sonarqube?useUnicode=true&amp;characterEncoding=utf8 </sonar.jdbc.url> <sonar.jdbc.username>root</sonar.jdbc.username> <sonar.jdbc.password>wusc.123</sonar.jdbc.password> <!-- Optional URL to server. Default value is http://localhost:9000 --> <sonar.host.url> http://localhost:9090/sonarqube </sonar.host.url> </properties> </profile> </profiles> <!--激活profile--> <activeProfiles> <activeProfile>edu</activeProfile> </activeProfiles> </settings> 3、 配置HudsonHome,在/root目录下创建HudsonHome目录,并配置到环境变量 mkdir HudsonHome 切换到root用户,在/etc/profile中配置全局环境变量 vi /etc/profile hudson env export HUDSON_HOME=/root/HudsonHome source /etc/profile 4、 下载最新版Tomcat7,当前最新版为7.0.59: wget http://apache.fayea.com/tomcat/tomcat-7/v7.0.59/bin/apache-tomcat-7.0.59.tar.gz 5、 解压安装Tomcat: tar -zxvf apache-tomcat-7.0.59.tar.gz mv apache-tomcat-7.0.59 hudson-tomcat 移除/root/hudson-tomcat/webapps目录下的所有文件: rm -rf /root/hudson-tomcat/webapps/* 将Tomcat容器的编码设为UTF-8: vi /root/hudson-tomcat/conf/server.xml ``` Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" / ``` 如果不把Tomcat容器的编码设为UTF-8,在以后配置Hudson是有下面的提示: 设置hudson-tomcat的内存 vi /root/hudson-tomcat/bin/catalina.sh !/bin/sh 下面增加: JAVA_OPTS='-Xms512m -Xmx2048m' 6、 下载最新版的Hudson(这里是3.2.2版)包: wget http://mirror.bit.edu.cn/eclipse/hudson/war/hudson-3.2.2.war 将war包拷贝到hudson-tomcat/weapps目录,并重命名为hudson.war cp /root/hudson-3.2.2.war /root/hudson-tomcat/webapps/hudson.war 7、 防火墙开启8080端口,用root用户修改/etc/sysconfig/iptables, vi /etc/sysconfig/iptables 增加: hudson-tomcat port:8080 -A INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -j ACCEPT 重启防火墙: service iptables restart 8、 设置hudson-tomcat开机启动: 在虚拟主机中编辑/etc/rc.local文件, vi /etc/rc.local 加入: /root/hudson-tomcat/bin/startup.sh 9、 启动hudson-tomcat /root/hudson-tomcat/bin/startup.sh 10、 配置Hudson: (1)浏览器输入:http://192.168.4.221:8080/hudson/ 初始化安装需要安装3个默认勾选中的插件(如上图红色部分),其它插件可以等初始化安装完成之后再选择安装。 点击“Install”安装按钮后,需要等待一会时间才能安装完成。安装完成后按“Finish”按钮。 安装的插件保存在 /root/HudsonHome/plugins 目录。 (2)初始化完成后就会进行Hudson的配置管理界面: 安全配置 启用安全配置 使用项目矩阵授权策略 注册一个超级管理员账号 系统设置 配置系统信息、JDK、Maven 保存后的效果 插件安装 结合我们想要实现的持续集成功能,需要安装如下几个插件。如想集成更多功能,自行添加插件并配置则可。(注意:现在我们使用了SonarQube质量管理不台,则不再需要在Hudson中单独去安装CheckStyle、Findbugs、PMD、Cobertura等Sonar中已有的插件) 逐个搜索你想要安装的插件并点击安装,安装完之后重启Hudson。 如下图所示: 在Hudson中配置SonarQube链接 以上就是Hudson的基本安装和配置,更多其它配置和功能可自行扩展。 Hudson的使用(使用Hudson来自动化编译、分析、打包、发布、部署项目) 添加项目 查看视频教程>>基于Dubbo的分布式系统架构实战
一、SonarQube的配置(前提,先用admin用户登录)1、 安装中文汉化包:Setting >> Update Center >> Available Plugins >> LOCALIZATION >> Chinese Pack Install 安装完汉化包之后需要重启SonarQube才能生效(重启前可顺便把CheckStyle、PMD等插件安装一下) /root/sonarqube/bin/linux-x86-64/sonar.sh restartStopping SonarQube...Stopped SonarQube.Starting SonarQube...Started SonarQube. 重启完之后刷新SonarQube:http://192.168.4.221:9090/sonarqube/汉化成功(注意,汉化包并没有完全汉化),重新登录 2、 MyEclipse/Eclipse中安装SonarQube插件的安装、配置、使用:http://docs.sonarqube.org/display/SONAR/SonarQube+in+Eclipsehttp://docs.sonarqube.org/display/SONAR/Installing+SonarQube+in+Eclipsehttp://docs.sonarqube.org/display/SONAR/Configuring+SonarQube+in+Eclipsehttp://docs.sonarqube.org/display/SONAR/Working+with+SonarQube+in+Eclipse(请参考官方文档操作,在此不作讲解,我们重点讲SonarQube结合Maven插件的使用) 3、 Maven分析器插件的配置与使用http://docs.sonarqube.org/display/SONAR/Installing+and+Configuring+Maven在Maven本地库中的settings.xml(我这里是settings_edu.xml)配置文件中的节点中添加如下配置: <profile> <id>sonar</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <!-- Example for MySQL--> <sonar.jdbc.url> jdbc:mysql://192.168.4.221:3306/sonarqube?useUnicode=true&amp;characterEncoding=utf8 </sonar.jdbc.url> <sonar.jdbc.username>root</sonar.jdbc.username> <sonar.jdbc.password>wusc.321</sonar.jdbc.password> <!-- Optional URL to server. Default value is http://localhost:9000 --> <sonar.host.url>http://192.168.4.221:9090/sonarqube</sonar.host.url> </properties> </profile> 使用Maven分析器进行分析,命令:纯Maven命令:mvn clean install sonar:sonarMyEclipse中执行:clean install sonar:sonar(如果你是第一次运行此命令,看执行日志你会发现它会先下载sonar-runner等插件)成功执行完分析命令后便可到Web Server中查看代码质量分析结果数据。 4、 配置:(1) 配置(2) 权限(3) 系统 5、 质量配置介绍(切换默认配置)6、 代码规则介绍(自定义规则)7、 问题处理介绍(质量管理的体现)8、 指表9、 仪表盘(自定义) 更多内容请关注:
IP:192.168.4.221环境:CentOS 6.6、JDK7、MySQL5.1 、SonarQube-4.5.4(LTS)root用户操作准备工作:已安装JDK7并配置好了环境变量 1 、安装MySQL5.1(可参考前面SVN管理平台的MySQL安装步骤,如果已安装则无需安装) rpm -qa | grep mysql ## 查看该操作系统上是否已经安装了mysql数据库,有的话,可以通过 rpm -e 命令 或者 rpm -e --nodeps 命令来卸载掉 yum install mysql-server mysql mysql-devel service mysqld start chkconfig --list | grep mysqldmysqld 0:off 1:off 2:off 3:off 4:off 5:off 6:off用上面的命令查看到MySQL并没有设置开机启动,所以需要设置开机启动 chkconfig mysqld on 为了方便远程管理,防火墙中打开3306端口 vi /etc/sysconfig/iptables-A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT重启防火墙,使端口配置生效 service iptables restart 设置MySQL数据库root用户的密码: mysqladmin -u root password 'wusc.123'登录数据库: mysql -u root -p MySQL授权远程访问(先用root登录mysql)mysql> GRANT ALL PRIVILEGES ON . TO 'root'@'%' IDENTIFIED BY 'wusc.321' WITH GRANT OPTION;mysql> FLUSH PRIVILEGES; 2、配置MySQL结合SonarQube,MySQL数据库最好使用InnoDB引擎,可提高性能。看你的mysql现在已提供什么存储引擎:mysql> show engines;看你的mysql当前默认的存储引擎:mysql> show variables like '%storage_engine%';修改MySQL存储引擎为InnoDB, 在配置文件/etc/my.cnf中的[mysqld] 下面加入default-storage-engine=INNODB vi /etc/my.cnf[mysqld]default-storage-engine=INNODB 重启mysql服务器 service mysqld restart 再次登录MySQL查看默认引擎设置是否生效 mysql> show variables like '%storage_engine%'; Variable_name Value storage_engine InnoDB innodb_buffer_pool_size 参数值设置得尽可能大一点这个参数主要作用是缓存innodb表的索引,数据,插入数据时的缓冲默认值:128M,专用mysql服务器设置的大小:操作系统内存的70%-80%最佳。设置方法:my.cnf文件[mysqld] 下面加入innodb_buffer_pool_size参数 vi /etc/my.cnf[mysqld]innodb_buffer_pool_size = 256M(我们这里设置为256M,因为我们的不是专用的MySQL数据库服务器,还有很多其他的服务需要占用系统内存) 设置MySQL的查询缓存query_cache_size ,最少设置15M vi /etc/my.cnf[mysqld]query_cache_type=1query_cache_size=32M 重启mysql服务器 service mysqld restart 验证缓存设置是否生效: mysql> show variables like '%query_cache%'; Variable_name Value have_query_cache YES query_cache_limit 1048576 query_cache_min_res_unit 4096 query_cache_size 33554432 query_cache_type ON query_cache_wlock_invalidate OFF 3、创建sonarqube数据库(UTF-8编码) 二、安装SonarQube的Web Server下载最新LTS版的SonarQube安装包(当前版本为sonarqube-4.5.4.zip):下载地址:http://www.sonarqube.org/downloads/http://dist.sonar.codehaus.org/sonarqube-4.5.4.zip下载: wget http://dist.sonar.codehaus.org/sonarqube-4.5.4.zip解压安装: unzip sonarqube-4.5.4.zip mv sonarqube-4.5.4 sonarqube 编辑sonar配置: cd sonarqube/conf/ vi sonar.propertiessonar.jdbc.username=rootsonar.jdbc.password=wusc.123----- MySQL 5.xsonar.jdbc.url=jdbc:mysql://localhost:3306/sonarqube?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance sonar.web.host=0.0.0.0sonar.web.context=/sonarqubesonar.web.port=9090 保存以上配置(注意,要看看默认的9000端口是否已被占用) 防火墙中打开9090端口: vi /etc/sysconfig/iptables-A INPUT -m state --state NEW -m tcp -p tcp --dport 9090 -j ACCEPT重启防火墙,使端口配置生效 service iptables restart 启动 SonarQube Web Server /root/sonarqube/bin/linux-x86-64/sonar.sh start(初次启动会自动建表和做相应的初始化) 浏览器中输入:http://192.168.4.221:9090/sonarqube/ 登录,默认用户名/密码为 admin/admin 到此,SonarQube已安装完毕,接下来是对SonarQube做相应的配置和使用 参考内容:基于Dubbo的分布式系统架构实战
环境:CentOS 6.6 Final、JDK7、Sonatype Nexus、MavenIP:192.168.4.221root用户操作 前提:已安装JDK7并配置好了环境变量 1、下载最新版Nexus(本教程使用的是:nexus-2.11.2-03-bundle.tar.gz),下载地址:http://www.sonatype.org/nexus/go/ wget https://sonatype-download.global.ssl.fastly.net/nexus/oss/nexus-2.11.2-03-bundle.tar.gz 2、解压 mkdir nexus tar -zxvf nexus-2.11.2-03-bundle.tar.gz -C nexus cd nexus lsnexus-2.11.2-03 sonatype-work(一个nexus服务,一个私有库目录) 3、编辑Nexus的nexus.properties文件,配置端口和work目录信息(保留默认) cd nexus-2.11.2-03 lsbin conf lib LICENSE.txt logs nexus NOTICE.txt tmp查看目录结构,jetty运行 cd conf vi nexus.properties Jetty sectionapplication-port=8081application-host=0.0.0.0nexus-webapp=${bundleBasedir}/nexusnexus-webapp-context-path=/nexus Nexus sectionnexus-work=${bundleBasedir}/../sonatype-work/nexusruntime=${bundleBasedir}/nexus/WEB-INF 4、编辑nexus脚本, 配置RUN_AS_USER参数vi /root/nexus/nexus-2.11.2-03/bin/nexusRUN_AS_USER=改为:RUN_AS_USER=root 5、防火墙中打开8081端口 vi /etc/sysconfig/iptables添加:-A INPUT -m state --state NEW -m tcp -p tcp --dport 8081 -j ACCEPT保存后重启防火墙 service iptables restart 6、启动nexus /root/nexus/nexus-2.11.2-03/bin/nexus start WARNING - NOT RECOMMENDED TO RUN AS ROOT Starting Nexus OSS...Started Nexus OSS. 7、浏览器中打开:http://192.168.4.221:8081/nexus/ 8、登录,默认用户名admin,默认密码admin123: 到此,Nexus已安装完成,接下来是Nexus的配置 Nexus配置(登录后)1、菜单Administration/Server配置邮箱服务地址(如果忘记密码,可以通过该邮箱找回密码) 给用户配置邮箱地址,方便忘记密码时找回: 用户修改密码 2、仓库类型group 仓库组:Nexus 通过仓库组的概念统一管理多个仓库,这样我们在项目中直接请求仓库组即可请求到仓库组管理的多个仓库;hosted 宿主仓库:主要用于发布内部项目构件或第三方的项目构件(如购买商业的构件)以及无法从公共仓库获取的构件(如 oracle 的 JDBC 驱动)proxy 代理仓库:代理公共的远程仓库;virtual 虚拟仓库:用于适配 Maven 1;一般用到的仓库种类是hosted、proxy Hosted仓库常用类型说明:releases 内部的模块中release模块的发布仓库snapshots 发布内部的SNAPSHOT模块的仓库3rd party 第三方依赖的仓库,这个数据通常是由内部人员自行下载之后发布上去 如果构建的Maven项目本地仓库没有对应的依赖包,那么就会去Nexus私服去下载,如果Nexus私服也没有此依赖包,就回去远程中央仓库下载依赖,这些中央仓库就是proxy。 Nexus私服下载成功后再下载至本地Maven库供项目引用。 3、设置proxy代理仓库(Apache Snapshots/Central/Codehaus Snapshots)准许远程下载,如: 4、Maven本地库的安装与配置(请看参考视频的操作) 环境变量、setting.xml 5、MyEclipse中的Maven配置(请看参考视频的操作) 6、项目的构建与发布演示(请看参考视频的操作) 修改common-parent中的pom.xml中的私有库地址 7、上传第三方包操作演示 参考样例视频:基于Dubbo的分布式系统架构实战
CI服务器:192.168.4.221root用户操作 建议安装前更新操作系统yum update更新完成后重启 reboot 安装apache yum install httpd httpd-devel service httpd start chkconfig httpd on vi /etc/httpd/conf/httpd.conf找到 ServerName 并修改成ServerName localhost:80 防火墙中打开80端口: vi /etc/sysconfig/iptables-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT service iptables restart http://192.168.4.221/ 安装SVN服务 yum install mod_dav_svn subversion必须安装mod_dav_svn模块 安装完svn后要重启apache service httpd restart 查看测试是否安装svn模块 ls /etc/httpd/modules/ | grep svnmod_authz_svn.somod_dav_svn.so svn --version 创建svn库主目录(多库模式,一份配置文件管理多个库) mkdir /svn/ cd /etc/httpd/conf.d ls 此时可以看到一个subversion.conf配置文件(是在安装mod_dav_svn模块时生成的) vi subversion.conf添加以下内容Include /svn/httpd.confLocation /svn/DAV svnSVNListParentPath onSVNParentPath /svnAuthType BasicAuthName "Subversion repositories"AuthUserFile /svn/passwd.httpAuthzSVNAccessFile /svn/authzRequire valid-user/LocationRedirectMatch ^(/svn)$ $1/ 创建/svn/passwd.http和/svn/authz touch /svn/passwd.http touch /svn/authz 重启apache service httpd restart 安装jsvnadminsvnadmin介绍(在Google Code上,需要FQ才能下载。我们也会把最新版的jsvnadmin放到群共享中)https://code.google.com/p/jsvnadmin/https://jsvnadmin.googlecode.com/files/svnadmin-3.0.5.zip 安装MySQL(单独安装,与业务系统的数据库分开) rpm -qa | grep mysql ## 查看该操作系统上是否已经安装了mysql数据库,有的话,可以通过 rpm -e 命令 或者 rpm -e --nodeps 命令来卸载掉 yum install mysql-server mysql mysql-devel service mysqld start chkconfig --list | grep mysqldmysqld 0:off 1:off 2:off 3:off 4:off 5:off 6:off用上面的命令查看到MySQL并没有设置开机启动,所以需要设置开机启动 chkconfig mysqld on 为了方便远程管理,防火墙中打开3306端口 vi /etc/sysconfig/iptables-A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT重启防火墙,使端口配置生效 service iptables restart 设置MySQL数据库root用户的密码: mysqladmin -u root password 'wusc.123'登录数据库: mysql -u root -p MySQL授权远程访问(先用root登录mysql)mysql> GRANT ALL PRIVILEGES ON . TO 'root'@'%' IDENTIFIED BY 'wusc.321' WITH GRANT OPTION;mysql> FLUSH PRIVILEGES; 使用Tomcat7部署svnadmin cd /root使用wget下载最新版的tomcat7 的tar.gz包 tar -zxvf apache-tomcat-7.0.xx.tar.gz mv apache-tomcat-7.0.xx svnadmin-tomcat 修改Tomcat的端口为9000和容器编码为UTF-8 vi /root/svnadmin-tomcat/conf/server.xml修改以下标红的内容Server port="9005" shutdown="SHUTDOWN"Connector port="9000" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" / 防火墙中打开9000端口 vi /etc/sysconfig/iptables-A INPUT -m state --state NEW -m tcp -p tcp --dport 9000 -j ACCEPT重启防火墙,使端口配置生效 service iptables restart cd /root/svnadmin-tomcat/webapps rm -rf * 上传 svnadmin.war 到/root/svnadmin-tomcat/webapps目录 cd /root/svnadmin-tomcat/webapps解压 unzip svnadmin.war -d svnadmin备份 mv svnadmin.war /root/tools/ cd svnadmin/WEB-INF vi jdbc.properties内容改为如下db=MySQLMySQLMySQL.jdbc.driver=com.mysql.jdbc.DriverMySQL.jdbc.url=jdbc:mysql://127.0.0.1:3306/svnadmin?characterEncoding=utf-8MySQL.jdbc.username=rootMySQL.jdbc.password=wusc.123 创建svnadmin数据库并导入相应数据(UTF-8编码)执行db/mysql5.sql 和 db/lang/en.sql 启动svnadmin-tomcat /root/svnadmin-tomcat/bin/startup.sh浏览器中打开:http://192.168.4.221:9000/svnadmin/ 如:输入admin,wusc.123 创建库 此时:/svn/目录下会创建一个wusc_edu的SVN库目录。同时也会多出一个httpd.conf文件,内容与subversion.conf一样,在/etc/httpd/conf.d/subversion.conf中已配置。/svn/authz 授权文件中会多出如下内容:[aliases][groups]wusc_edu_developer=wusc_edu_manager=wusc_edu_tester= [wusc_edu:/]@wusc_edu_manager=rw 以上过程其实是调用了svn对应的命令做了相应的操作 配置库目录权限 cd /svn chown -R apache.apache wusc_edu chmod -R 777 wusc_edu(如创建新库,需要对新建的库目录执行以上两步授权操作) 关闭SELinux(Linux的访问控制)修改/etc/selinux/config 文件 vi /etc/selinux/config将SELINUX=enforcing改为SELINUX=disabled重启机器即可 reboot SVN版本管理平台(Subversion+Apache+Jsvnadmin)的使用: 先安装SVN管理客户端TortoiseSVN,方便对SVN库的操作和管理http://tortoisesvn.net/downloads.html(注意64位系统要安装64位版) 接下来可以对wusc_edu库进行相应的操作(1) 用户组(2) 用户(3) 授权(4) 导入项目
一、监控中心服务接口调用统计报表的显示配置 1、 Dubbo服务提供者和服务消费者中的spring配置文件中增加以下配置: !-- 监控中心配置 --!-- 监控中心协议,如果为protocol="registry",表示从注册中心发现监控中心地址,否则直连监控中心 --!-- 直连监控中心服务器地址,如:address="192.168.3.71:7070" --dubbo:monitor protocol="registry"/ 配置截图如下: 添加完以上配置后,重新构建部署Dubbo服务和服务消费者应用。 2、 Dubbo简易监控中心的配置解释(不需要修改,使用默认配置)操作系统用户为wusc,系统用户目录为/home/wuscdubbo-monitor的安装目录为:/home/wusc/dubbo-monitordubbo-monitor的配置文件为:/home/wusc/dubbo-monitor/conf/dubbo.propertiesdubbo-monitor的配置文件内容如下: dubbo.container=log4j,spring,registry,jettydubbo.application.name=simple-monitordubbo.application.owner=dubbo.registry.address=zookeeper://192.168.3.71:2181dubbo.protocol.port=7070dubbo.jetty.port=8090dubbo.jetty.directory=${user.home}/monitordubbo.charts.directory=${dubbo.jetty.directory}/chartsdubbo.statistics.directory=${user.home}/monitor/statisticsdubbo.log4j.file=logs/dubbo-monitor-simple.logdubbo.log4j.level=WARN 看上面配置文件中标红的的3行内容,理解${user.home}这个变量的意思则可,${user.home}指的就是启动dubbo-monitor程序的操作系统用户目录。我们这里用的是wusc用户,那么就是/home/wusc目录(如果是root用户启动,那就是/root)。此时,配置中3个目录的绝对路径为:dubbo.jetty.directory=/home/wusc/monitordubbo.charts.directory=/home/wusc/monitor/chartsdubbo.statistics.directory=/home/wusc/monitor/statistics 3、 重新启动dubbo-monitor简易监控中心,此时就会看到以上3个目录会被创新,并在目录里面有相应的服务接口调用的报表数据。 4、 此时再进入Dubbo简易监控中心就能查看到对应的报表数据
IP: 192.168.2.61部署容器:apache-tomcat-7.0.57端口:8080应用:edu-web-boss.war 1、 下载(或上传)最新版的Tomcat7:$wget http://mirrors.hust.edu.cn/apache/tomcat/tomcat-7/v7.0.57/bin/apache-tomcat-7.0.57.tar.gz 2、 规范安装目录:/home/wusc/edu/web/xxx-tomcat如:/home/wusc/edu/web/boss-tomcat 3、 解压安装$ mkdir –p /home/wusc/edu/web$ tar -zxvf apache-tomcat-7.0.57.tar.gz$ mv apache-tomcat-7.0.57 /home/wusc/edu/web/boss-tomcat 4、 移除/home/wusc/edu/web/boss-tomcat/webapps目录下的所有文件:$ rm -rf /home/wusc/edu/web/boss-tomcat/webapps/* 5、 上传Dubbo服务消费者Web应用war包edu-web-boss.war到/home/wusc/edu/web/boss-tomcat/webapps 6、 防火墙开启8080端口,用root用户修改/etc/sysconfig/iptables, vi /etc/sysconfig/iptables增加: boss-tomcat:8080-A INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -j ACCEPT重启防火墙: service iptables restart 7、 Tomat内存设置:$ vi /home/wusc/edu/web/boss-tomcat/bin/catalina.sh!/bin/shJAVA_OPTS='-Xms128m -Xmx512m -XX:PermSize=128m' 8、 启动Tomat7$ /home/wusc/edu/web/boss-tomcat/bin/startup.sh 9、 浏览http://192.168.2.61:8080/edu-web-boss 10、 配置Tomcat开机启动:在虚拟主机中编辑/etc/rc.local文件,加入:su - wusc -c '/home/wusc/edu/web/boss-tomcat/bin/startup.sh'
Dubbo管控台可以对注册到zookeeper注册中心的服务或服务消费者进行管理,但管控台是否正常对Dubbo服务没有影响,管控台也不需要高可用,因此可以单节点部署。 IP: 192.168.3.71部署容器:apache-tomcat-7.0.57端口:8080 1、 下载最新版的Tomcat7:$wget http://mirrors.hust.edu.cn/apache/tomcat/tomcat-7/v7.0.57/bin/apache-tomcat-7.0.57.tar.gz2、 解压:$ tar -zxvf apache-tomcat-7.0.57.tar.gz$ mv apache-tomcat-7.0.57 dubbo-admin-tomcat 3、 移除/home/wusc/dubbo-admin-tomcat/webapps目录下的所有文件:$ rm -rf * 4、 上传Dubbo管理控制台程序dubbo-admin-2.5.3.war到/home/wusc/dubbo-admin-tomcat/webapps 5、 解压并把目录命名为ROOT:$ unzip dubbo-admin-2.5.3.war -d ROOT把dubbo-admin-2.5.3.war移到/home/wusc/tools目录备份$ mv dubbo-admin-2.5.3.war /home/wusc/tools6、 配置dubbo.properties:$ vi ROOT/WEB-INF/dubbo.propertiesdubbo.registry.address=zookeeper://192.168.3.71:2181dubbo.admin.root.password=wusc.123dubbo.admin.guest.password=wusc.123(以上密码在正式上生产前要修改) 7、 防火墙开启8080端口,用root用户修改/etc/sysconfig/iptables, vi /etc/sysconfig/iptables增加: dubbo-admin-tomcat:8080-A INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -j ACCEPT重启防火墙: service iptables restart 8、 启动Tomat7$ /home/wusc/dubbo-admin-tomcat/bin/startup.sh 9、 浏览http://192.168.3.71:8080/ 10、 配置部署了Dubbo管控台的Tomcat开机启动:在虚拟主机中编辑/etc/rc.local文件,加入:su - wusc -c '/home/wusc/dubbo-admin-tomcat/bin/startup.sh'
分布式系统架构中,分布式事务问题是一个绕不过去的挑战。而微服务架构的流行,让分布式事问题日益突出!下面我们以电商购物支付流程中,在各大参与者系统中可能会遇到分布式事务问题的场景进行详细的分析!如上图所示,假设三大参与平台(电商平台、支付平台、银行)的系统都做了分布式系统架构拆分,按上数中的流程步骤进行分析:1、电商平台中创建订单:预留库存、预扣减积分、锁定优惠券,此时电商平台内各服务间会有分布式事务问题,因为此时已经要跨多个内部服务修改数据;2、支付平台中创建支付订单(选银行卡支付):查询账户、查询限制规则,符合条件的就创建支付订单并跳转银行,此时不会有分布式事务问题,因为还不会跨服务改数据;3、银行平台中创建交易订单:查找账户、创建交易记录、判断账户余额并扣款、增加积分、通知支付平台,此时也会有分布式事务问题(如果是服务化架构的话);4、支付平台收到银行扣款结果:更改订单状态、给账户加款、给积分帐户增加积分、生成会计分录、通知电商平台等,此时也会有分布式事务问题;5、电商平台收到支付平台的支付结果:更改订单状态、扣减库存、扣减积分、使用优惠券、增加消费积分等,系统内部各服务间调用也会遇到分布式事问题; 如上图,支付平台收到银行扣款结果后的内部处理流程:1、支付平台的支付网关对银行通知结果进行校验,然后调用支付订单服务执行支付订单处理;2、支付订单服务根据银行扣款结果更改支付订单状态;3、调用资金账户服务给电商平台的商户账户加款(实际过程中可能还会有各种的成本计费;如果是余额支付,还可能是同时从用户账户扣款,给商户账户加款);4、调用积分服务给用户积分账户增加积分;5、调用会计服务向会计(财务)系统写进交易原始凭证生成会计分录;6、调用通知服务将支付处理结果通知电商平台; 如上图,把支付系统中的银行扣款成功回调处理流程提取出来,对应的分布式事务问题的代码场景:/ 支付订单处理 /@Transactional(rollbackFor = Exception.class)public void completeOrder() { orderDao.update(); // 订单服务本地更新订单状态 accountService.update(); // 调用资金账户服务给资金帐户加款 pointService.update(); // 调用积分服务给积分帐户增加积分 accountingService.insert(); // 调用会计服务向会计系统写入会计原始凭证 merchantNotifyService.notify(); // 调用商户通知服务向商户发送支付结果通知} 本地事务控制还可行吗? 以上分布式事务问题,需要多种分布式事务解决方案来进行处理。 订单处理:本地事务 资金账户加款、积分账户增加积分:TCC型事务(或两阶段提交型事务),实时性要求比较高,数据必须可靠。 会计记账:异步确保型事务(基于可靠消息的最终一致性,可以异步,但数据绝对不能丢,而且一定要记账成功) 商户通知:最大努力通知型事务(按规律进行通知,不保证数据一定能通知成功,但会提供可查询操作接口进行核对) 龙果支付系统(开源版)face/2at3STmQikTePfpe6FRDEc3TRBeTw6NY.jpg开源中国地址:http://www.oschina.net/p/roncoo-pay http://git.oschina.net/roncoocom/roncoo-pay GitHub地址:https://github.com/roncoo/roncoo-pay在线支付演示:http://demo.pay.roncoo.com后台运营管理:http://demo.pay.roncoo.com/boss
作为大数据平台系统级的研发人员, 熟练Hadoop、Spark、Storm等主流大数据平台的核心框架。深入掌握如何编写MapReduce的作业及作业流的管理完成对数据的计算,并能够使用Hadoop提供的通用算法, 熟练掌握Hadoop整个生态系统的组件如: Yarn,HBase、Hive、Pig等重要组件,能够实现对平台监控、辅助运维系统的开发。
通过学习一系列面向开发者的Hadoop、Spark等大数据平台开发技术,掌握设计开发大数据系统或平台的工具和技能,能够从事分布式计算框架如Hadoop、Spark群集环境的部署、开发和管理工作,如性能改进、功能扩展、故障分析等。
大数据的难点在于它的生态系统太庞杂,家族血统太混乱,面对一个企业场景有n多的方案说“我行,我不是一般人”。就好比吃顿午餐,既可以端着碗吃,也可以就着锅吃,甚至倒到桌上手抓。每种吃法都能吃饱,但有的吃相很自然、很舒服,有的吃法很别扭,很猥琐。如何温文尔雅、如沐春风这就体现架构师的水平了。
这里分享一个在国内一线互联网公司实际工作经验,整理提炼的一套侧重培养大数据架构师级别的实战课程,讲重点介绍大数据在一线企业中的使用方案,对于各个组件,除了详细介绍必须掌握的操作要领,更重点介绍不同业务场景下的设计和应用技巧。绝不同于市面上大多数的操作手册朗读者。
包括如下几个层面:
1.大数据集成:主要介绍目前很火的ELK框架中的filebeat和logstash,相比较flume更轻量、更容易上手。
2.大数据传输:主要介绍kafka的原理和使用技巧
3.大数据落地:主要介绍hive和hbase这两款标准组合的原理和使用,并结合具体的业务场景揭秘高级设计和应用。
4.大数据使用:主要介绍企业中最有用的sql on hive、sql on hbase的解决方案,如何让hive速度提升十倍,如何让hbase像个rdbms,如何在hive中实现scd2等实际问题。
5.大数据搜索引擎:主要介绍目前很火的ELK框架中Elasticsearch,并详细演示从常规操作到高阶查询的全实战内容。
初创时期由于时间紧迫,在各种资源有限的情况下,通常就直接在项目目录下建立静态文件夹,用于用户存放项目中的文件资源。如果按不同类型再细分,可以在项目目录下再建立不同的子目录来区分。例如:resourcesstaticfile、resourcesstaticimg等。
优点:这样做比较便利,项目直接引用就行,实现起来也简单,无需任何复杂技术,保存数据库记录和访问起来也很方便。
缺点:如果只是后台系统的使用一般也不会有什么问题,但是作为一个前端网站使用的话就会存在弊端。一方面,文件和代码耦合在一起,文件越多存放越混乱;另一方面,如果流量比较大,静态文件访问会占据一定的资源,影响正常业务进行,不利于网站快速发展,分布式文件系统FastDFS详解-博客-云栖社区-阿里云 https://yq.aliyun.com/articles/338476?spm=5176.8091938.0.0.781e13c9A1T3sl
电视收视率项目,案例是国内的一家广电企业作为非洲国家的一个运营商,以用户收视行为数据作为基础数据,通过对频道和节目的分析,采用多维度统计分析的方法挖掘用户的收视行为特征。这个是围绕一个大数据整理流程而做的,可以了解大数据不同技术的相互协调,从收集数据,过滤数据,数据分析,数据展示
http://www.roncoo.com/course/view/d6270b0218bb44e6a894dd93de5228c1