首页 文章 精选 留言 我的

精选列表

搜索[Transformer架构],共10005篇文章
优秀的个人博客,低调大师

【架构实战】账户系统架构:资金安全是底线

## 一、账户系统出问题,是真正的灾难 2020年,我们支付系统出现一个严重Bug: - 用户A充值100元 - 系统记录:账户余额+100,但流水记录失败 - 用户A查询余额显示100元 - 但后台对账发现异常:账户余额 ≠ 流水汇总 **更严重的问题:** - 用户B提现100元 - 系统扣减余额成功,但提现记录失败 - 用户B余额显示正确,但钱没到账 **影响:** - 用户投诉 - 资金损失 - 监管风险 - 团队追责 从那以后,我们把账户系统作为最核心的系统来设计,**资金安全是底线**。 --- ## 二、账户系统核心模型 ### 2.1 账户模型 ``` ┌─────────────────────────────────────────────────────────────────┐ │ 账户系统核心模型 │ │ │ │ 用户账户(Account) │ │ ├── 账户ID │ │ ├── 用户ID │ │ ├── 账户类型(余额账户、积分账户、押金账户) │ │ ├── 余额 │ │ ├── 冻结金额 │ │ └── 版本号(乐观锁) │ │ │ │ 账户流水(Transaction) │ │ ├── 流水ID │ │ ├── 账户ID │ │ ├── 业务订单号 │ │ ├── 交易类型(充值、提现、消费、退款) │ │ ├── 交易金额 │ │ ├── 交易前余额 │ │ ├── 交易后余额 │ │ └── 交易时间 │ │ │ └──────────────────────────────────────────────────────────────────┘ ``` ### 2.2 账户表设计 ```sql -- 账户主表 CREATE TABLE account ( id BIGINT PRIMARY KEY AUTO_INCREMENT, account_no VARCHAR(32) NOT NULL COMMENT '账户号', user_id BIGINT NOT NULL COMMENT '用户ID', account_type TINYINT NOT NULL COMMENT '账户类型:1余额 2积分 3押金', balance DECIMAL(12,2) NOT NULL DEFAULT 0 COMMENT '余额', frozen_amount DECIMAL(12,2) NOT NULL DEFAULT 0 COMMENT '冻结金额', version INT NOT NULL DEFAULT 0 COMMENT '版本号', status TINYINT NOT NULL DEFAULT 1 COMMENT '状态:1正常 2冻结 3销户', create_time DATETIME NOT NULL, update_time DATETIME NOT NULL, UNIQUE KEY uk_account_no (account_no), UNIQUE KEY uk_user_type (user_id, account_type), INDEX idx_user_id (user_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='账户主表'; -- 账户流水表 CREATE TABLE account_transaction ( id BIGINT PRIMARY KEY AUTO_INCREMENT, transaction_no VARCHAR(64) NOT NULL COMMENT '流水号', account_no VARCHAR(32) NOT NULL COMMENT '账户号', biz_order_no VARCHAR(64) COMMENT '业务订单号', transaction_type TINYINT NOT NULL COMMENT '交易类型', amount DECIMAL(12,2) NOT NULL COMMENT '交易金额(正数入账,负数出账)', balance_before DECIMAL(12,2) NOT NULL COMMENT '交易前余额', balance_after DECIMAL(12,2) NOT NULL COMMENT '交易后余额', remark VARCHAR(255) COMMENT '备注', create_time DATETIME NOT NULL, UNIQUE KEY uk_transaction_no (transaction_no), INDEX idx_account_no (account_no), INDEX idx_biz_order_no (biz_order_no), INDEX idx_create_time (create_time) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='账户流水表'; ``` --- ## 三、账户核心操作 ### 3.1 充值流程 ```java /** * 充值服务 */ @Service @Slf4j public class RechargeService { @Autowired private AccountMapper accountMapper; @Autowired private TransactionMapper transactionMapper; @Transactional(rollbackFor = Exception.class) public RechargeResult recharge(RechargeRequest request) { // 1. 参数校验 validateRequest(request); // 2. 幂等性检查 if (transactionMapper.existsByBizOrderNo(request.getBizOrderNo())) { return RechargeResult.success("重复充值,已处理"); } // 3. 查询账户 Account account = accountMapper.selectByUserIdAndType( request.getUserId(), AccountType.BALANCE ); if (account == null) { throw new BusinessException("账户不存在"); } // 4. 乐观锁更新余额 BigDecimal balanceBefore = account.getBalance(); BigDecimal balanceAfter = balanceBefore.add(request.getAmount()); int rows = accountMapper.updateBalance( account.getId(), balanceAfter, account.getVersion() ); if (rows == 0) { throw new BusinessException("余额更新失败,请重试"); } // 5. 记录流水 Transaction transaction = new Transaction(); transaction.setTransactionNo(generateTransactionNo()); transaction.setAccountNo(account.getAccountNo()); transaction.setBizOrderNo(request.getBizOrderNo()); transaction.setTransactionType(TransactionType.RECHARGE); transaction.setAmount(request.getAmount()); transaction.setBalanceBefore(balanceBefore); transaction.setBalanceAfter(balanceAfter); transaction.setRemark("用户充值"); transactionMapper.insert(transaction); // 6. 发送充值成功事件 eventPublisher.publish(new RechargeSuccessEvent( request.getUserId(), request.getAmount() )); return RechargeResult.success(transaction.getTransactionNo()); } } ``` ### 3.2 提现流程 ```java /** * 提现服务 */ @Service @Slf4j public class WithdrawService { @Autowired private AccountService accountService; @Autowired private TransactionMapper transactionMapper; @Autowired private WithdrawOrderMapper withdrawOrderMapper; @Transactional(rollbackFor = Exception.class) public WithdrawResult withdraw(WithdrawRequest request) { // 1. 参数校验 validateRequest(request); // 2. 查询账户 Account account = accountService.getAccount( request.getUserId(), AccountType.BALANCE ); // 3. 检查余额 if (account.getBalance().compareTo(request.getAmount()) = #{amount} AND status = 1 """) int freezeAmount( @Param("accountNo") String accountNo, @Param("amount") BigDecimal amount ); } ``` ### 4.2 流水记录完整性 ```java /** * 账户流水服务 */ @Service @Slf4j public class TransactionService { /** * 记录交易流水(本地事务内) */ public void recordTransaction( String accountNo, String bizOrderNo, Integer transactionType, BigDecimal amount ) { // 1. 查询账户当前余额 Account account = accountMapper.selectByAccountNo(accountNo); // 2. 计算交易前后余额 BigDecimal balanceBefore = account.getBalance(); BigDecimal balanceAfter = balanceBefore.add(amount); // 3. 记录流水 Transaction transaction = new Transaction(); transaction.setTransactionNo(generateTransactionNo()); transaction.setAccountNo(accountNo); transaction.setBizOrderNo(bizOrderNo); transaction.setTransactionType(transactionType); transaction.setAmount(amount); transaction.setBalanceBefore(balanceBefore); transaction.setBalanceAfter(balanceAfter); transactionMapper.insert(transaction); log.info("记录流水: transactionNo={}, accountNo={}, amount={}", transaction.getTransactionNo(), accountNo, amount); } /** * 生成流水号(全局唯一) */ private String generateTransactionNo() { // 格式:日期(8位) + 机器ID(4位) + 序列号(12位) String date = DateUtil.format(new Date(), "yyyyMMdd"); String machineId = String.format("%04d", machineIdProvider.getMachineId()); String sequence = String.format("%012d", sequenceGenerator.next()); return date + machineId + sequence; } } ``` ### 4.3 账务一致性校验 ```java /** * 账务一致性校验服务 */ @Service @Slf4j public class AccountReconcileService { @Autowired private AccountMapper accountMapper; @Autowired private TransactionMapper transactionMapper; /** * 账务一致性校验 */ @Scheduled(cron = "0 0 2 * * ?") // 每天凌晨2点执行 public void reconcile() { log.info("开始账务一致性校验..."); // 1. 查询所有账户 List accounts = accountMapper.selectAll(); for (Account account : accounts) { // 2. 计算流水汇总 BigDecimal sumAmount = transactionMapper.sumAmountByAccountNo( account.getAccountNo() ); // 3. 对比账户余额和流水汇总 if (account.getBalance().compareTo(sumAmount) != 0) { log.error("账务不一致: accountNo={}, balance={}, sumAmount={}", account.getAccountNo(), account.getBalance(), sumAmount); // 4. 记录异常,人工处理 reconcileErrorMapper.insert(new ReconcileError( account.getAccountNo(), account.getBalance(), sumAmount, account.getBalance().subtract(sumAmount) )); // 5. 发送告警 alertService.sendAlert("账务异常", String.format("账户%s余额不一致,差额%.2f", account.getAccountNo(), account.getBalance().subtract(sumAmount))); } } log.info("账务一致性校验完成"); } /** * 账户余额修复(需要审批) */ @Transactional(rollbackFor = Exception.class) public void fixAccountBalance(String accountNo, BigDecimal correctBalance) { Account account = accountMapper.selectByAccountNo(accountNo); // 记录调整流水 BigDecimal adjustAmount = correctBalance.subtract(account.getBalance()); Transaction transaction = new Transaction(); transaction.setTransactionNo(generateTransactionNo()); transaction.setAccountNo(accountNo); transaction.setTransactionType(TransactionType.ADJUST); transaction.setAmount(adjustAmount); transaction.setBalanceBefore(account.getBalance()); transaction.setBalanceAfter(correctBalance); transaction.setRemark("账务修复"); transactionMapper.insert(transaction); // 更新账户余额 accountMapper.updateBalance(account.getId(), correctBalance, account.getVersion()); } } ``` --- ## 五、分布式事务方案 ### 5.1 TCC事务方案 ```java /** * 账户TCC事务 */ @Service public class AccountTccService { /** * Try:冻结余额 */ public boolean tryFreeze(String accountNo, BigDecimal amount) { return accountMapper.freezeAmount(accountNo, amount) > 0; } /** * Confirm:扣减冻结余额 */ public boolean confirmDeduct(String accountNo, BigDecimal amount) { return accountMapper.deductFrozenAmount(accountNo, amount) > 0; } /** * Cancel:解冻余额 */ public boolean cancelFreeze(String accountNo, BigDecimal amount) { return accountMapper.unfreezeAmount(accountNo, amount) > 0; } } /** * 支付TCC事务协调器 */ @Service public class PaymentTccCoordinator { @Autowired private AccountTccService accountTccService; @Autowired private OrderTccService orderTccService; @GlobalTransactional public void pay(Long userId, Long orderId, BigDecimal amount) { // Try阶段 boolean accountTry = accountTccService.tryFreeze(userId, amount); boolean orderTry = orderTccService.tryPay(orderId, amount); if (!accountTry || !orderTry) { throw new BusinessException("Try阶段失败"); } // Confirm阶段(Seata自动提交) // 如果失败,自动执行Cancel } } ``` ### 5.2 本地消息表方案 ```java /** * 本地消息表方案 */ @Service @Slf4j public class LocalMessageService { @Autowired private AccountMapper accountMapper; @Autowired private MessageMapper messageMapper; /** * 充值(本地事务) */ @Transactional(rollbackFor = Exception.class) public void recharge(RechargeRequest request) { // 1. 更新账户余额 accountMapper.updateBalance(...); // 2. 记录流水 transactionMapper.insert(...); // 3. 写入本地消息表(同一事务) LocalMessage message = new LocalMessage(); message.setMessageId(UUID.randomUUID().toString()); message.setTopic("recharge-success"); message.setMessageBody(JSON.toJSONString(request)); message.setStatus(MessageStatus.PENDING); messageMapper.insert(message); } /** * 消息发送任务 */ @Scheduled(fixedDelay = 5000) public void sendMessage() { List messages = messageMapper.selectPending(); for (LocalMessage message : messages) { try { // 发送MQ消息 rocketMQTemplate.send(message.getTopic(), message.getMessageBody()); // 更新状态为已发送 messageMapper.updateStatus(message.getMessageId(), MessageStatus.SENT); } catch (Exception e) { log.error("消息发送失败: {}", message.getMessageId(), e); } } } } ``` --- ## 六、踩坑实录 ### 坑1:余额更新丢失 > **问题**:并发更新余额时,后提交的请求覆盖前一个请求。 **踩坑场景**: - 用户余额100元 - 同时发起两个请求:充值50元、消费30元 - 理想结果:余额120元 - 实际结果:余额可能为80元或150元 **解决方案**:使用乐观锁 ```java @Update(""" UPDATE account SET balance = balance + #{delta}, version = version + 1 WHERE id = #{id} AND version = #{version} """) int updateBalanceWithVersion( @Param("id") Long id, @Param("delta") BigDecimal delta, @Param("version") Integer version ); ``` ### 坑2:流水记录缺失 > **问题**:余额更新成功,但流水记录失败。 **踩坑场景**: 数据库连接池满,流水插入失败,但余额已更新。 **解决方案**:本地事务 + 本地消息表 ```java @Transactional(rollbackFor = Exception.class) public void recharge(RechargeRequest request) { // 同一事务内,要么都成功,要么都失败 accountMapper.updateBalance(...); transactionMapper.insert(...); } ``` ### 坑3:幂等性缺失 > **问题**:同一请求重复处理,导致余额重复增加。 **踩坑场景**: 用户充值请求超时重试,系统处理了两次。 **解决方案**:业务订单号去重 ```java public void recharge(RechargeRequest request) { // 检查是否已处理 if (transactionMapper.existsByBizOrderNo(request.getBizOrderNo())) { return; // 已处理,直接返回 } // 处理充值 ... } ``` ### 坑4:账户并发热点 > **问题**:热门账户(如平台账户)并发量大,成为热点。 **踩坑场景**: 所有用户消费都要扣减平台账户余额,该账户成为热点。 **解决方案**:热点账户分片 ```java // 平台账户分片:account_0, account_1, ..., account_9 String accountNo = "platform_" + (userId % 10); // 查询时汇总 BigDecimal totalBalance = accountMapper.sumBalance("platform_*"); ``` ### 坑5:对账数据量大 > **问题**:历史流水数据量大,对账性能差。 **解决方案**:T+N对账 + 分区表 ```sql -- 流水表按月分区 CREATE TABLE account_transaction_202401 ( ... ) ENGINE=InnoDB; -- 只对最近7天数据对账 SELECT * FROM account_transaction WHERE create_time >= DATE_SUB(CURDATE(), INTERVAL 7 DAY); ``` --- ## 七、最佳实践 ### 7.1 账户系统安全检查清单 ``` 账户系统安全检查清单: □ 余额更新 □ 使用乐观锁或悲观锁 □ 本地事务保证原子性 □ 流水记录在同一事务 □ 流水记录 □ 每笔交易都有流水 □ 流水记录余额变化前后值 □ 流水号全局唯一 □ 幂等性 □ 业务订单号去重 □ 流水号唯一索引 □ 对账机制 □ T+1日终对账 □ 余额 = 流水汇总 □ 异常自动告警 □ 安全审计 □ 所有操作有日志 □ 敏感操作有审批 □ 数据变更有记录 ``` --- ## 八、总结 账户系统核心要点: | 要点 | 说明 | |------|------| | 原子性 | 余额更新和流水记录同一事务 | | 一致性 | 余额 = 流水汇总,每日对账 | | 幂等性 | 业务订单号去重 | | 可追溯 | 所有操作有记录 | | 安全性 | 敏感操作有审批 | **血的教训:** > 资金安全是底线。账户系统出问题,不是丢数据,是丢信任。 --- *个人观点,仅供参考*

优秀的个人博客,低调大师

LNMP架构(架构介绍,mysql安装,php安装,nginx介绍)

一、LNMP建构介绍 和LAMP不同的是,提供web服务的是Nginx 并且php是作为一个独立服务存在的,这个服务叫做php-fpm Nginx直接处理静态文件请求,动态请求会转发给php-fpm apache和nginx的区别;https://www.cnblogs.com/huangye-dream/p/3550328.html nginx相对于apache的优点: 轻量级,同样起web 服务,比apache 占用更少的内存及资源抗并发,nginx 处理请求是异步非阻塞的,而apache 则是阻塞型的,在高并发下nginx 能保持低资源低消耗高性能高度模块化的设计,编写模块相对简单社区活跃,各种高性能模块出品迅速啊 apache 相对于nginx 的优点:rewrite ,比nginx 的rewrite 强大模块超多,基本想到的都可以找到少bug ,nginx 的bug 相对较多 异步和同步: 同步:你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。 异步:书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。 阻塞和非阻塞: 你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。 在这里阻塞与非阻塞与是否同步异步无关。跟老板通过什么方式回答你结果无关。 二、mysql的安装 [root@lnmp mysql]# cd /usr/local/src/ [root@lnmp mysql]# wgethttp://mirrors.sohu.com/mysql/MySQL-5.6/mysql-5.6.36-linux-glibc2.5-x86_64.tar.gz [root@lnmp mysql]# tar zxvf mysql-5.6.36-linux-glibc2.5-x86_64.tar.gz (解压mysql tar包) [root@lnmp mysql]# mv mysql-5.6.36-linux-glibc2.5-x86_64 /usr/local/mysql (移动解压包并改名) [root@lnmp mysql]# mkdir /data (创建储存的/data目录) [root@lnmp mysql]# useradd mysql (创建mysql用户) [root@lnmp mysql]# vim /etc/my.cnf (修改/etc/my.cnf文件) datadir=/data/mysql socket=/tmp/mysql.sock [root@lnmp mysql]# ./scripts/mysql_install_db --user=mysql --datadir=/data/mysql (初始化MySQL,并且指定用户和数据库目录,第一次安装时会报错,安装下面2个包就好) [root@lnmp mysql]# yum install autoconf -y [root@lnmp mysql]# yum install -y libaio [root@lnmp mysql]# ./scripts/mysql_install_db --user=mysql --datadir=/data/mysql [root@lnmp mysql]# cp support-files/mysql.server /etc/init.d/mysqld (复制启动脚本) [root@lnmp mysql]# vim /etc/init.d/mysqld (修改启动脚本里的basedir和datadir) 46 basedir=/usr/local/mysql 47 datadir=/data/mysql [root@lnmp mysql]# /etc/init.d/mysqld start (启动mysql) [root@lnmp mysql]# chkconfig --add mysqld (添加mysql到服务列表) [root@lnmp mysql]# chkconfig mysqld on (设置MySQL开机启动) 添加到服务列表后,就可以使用以下命令: [root@lnmp mysql]# service mysqld stop (启动MySQL) Shutting down MySQL.. SUCCESS! [root@lnmp mysql]# service mysqld start (关闭MySQL) Starting MySQL. SUCCESS! 三、PHP安装 [root@lnmp ~]#cd /usr/local/src (把源码包下载到指定目录) [root@lnmp ~]#wgethttp://cn2.php.net/distributions/php-5.6.30.tar.gz [root@lnmp ~]#tar zxf php-5.6.30.tar.gz [root@lnmp ~]# useradd -s /sbin/nologin php-fpm (添加php-fpm用户,-s指定不能登录) [root@lnmp ~]# cd php-5.6.30 [root@lnmp ~]# ./configure --prefix=/usr/local/php-fpm --with-config-file-path=/usr/local/php-fpm/etc --enable-fpm --with-fpm-user=php-fpm --with-fpm-group=php-fpm --with-mysql=/usr/local/mysql --with-mysqli=/usr/local/mysql/bin/mysql_config --with-pdo-mysql=/usr/local/mysql --with-mysql-sock=/tmp/mysql.sock --with-libxml-dir --with-gd --with-jpeg-dir --with-png-dir --with-freetype-dir --with-iconv-dir --with-zlib-dir --with-mcrypt --enable-soap --enable-gd-native-ttf --enable-ftp --enable-mbstring --enable-exif --with-pear --with-curl --with-openssl (编译php包,过程中可能有需要安装的包,导致的错误) [root@lnmp ~]# make && make install [root@lnmp ~]# cp php.ini-production /usr/local/php-fpm/etc/php.ini (复制目录并改名字) [root@lnmp ~]# vi /usr/local/php/etc/php-fpm.conf (修改php配置文件,以下内容) [global] 定义全局参数 pid = /usr/local/php-fpm/var/run/php-fpm.pid error_log = /usr/local/php-fpm/var/log/php-fpm.log [www] 一个模块的名字 listen = /tmp/php-fcgi.sock 监听的地址 listen.mode = 666 定义sock文件的权限 user = php-fpm 用户 group = php-fpm 用户组 pm = dynamic pm.max_children = 50 pm.start_servers = 20 pm.min_spare_servers = 5 pm.max_spare_servers = 35 pm.max_requests = 500 rlimit_files = 1024 [root@lnmp ~]# cp sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm (复制启动脚本到以下位置) [root@lnmp ~]# chmod 755 /etc/init.d/php-fpm [root@lnmp ~]# chkconfig --add php-fpm (添加php到服务) [root@lnmp ~]# chkconfig php-fpm on (设置开机启动php服务) [root@lnmp ~]# service php-fpm start (启动php服务) 四、nginx的介绍 •Nginx官网 nginx.org,最新版1.13,最新稳定版1.12 •Nginx应用场景:web服务、反向代理、负载均衡 •Nginx著名分支,淘宝基于Nginx开发的Tengine,使用上和Nginx一致,服务名,配置文件名都一样,和Nginx的最大区别在于Tenging增加了一些定制化模块,在安全限速方面表现突出,另外它支持对js,css合并 •Nginx核心+lua相关的组件和模块组成了一个支持lua的高性能web容器openresty 参考http://jinnianshilongnian.iteye.com/blog/2280928 本文转自 小新锐 51CTO博客,原文链接:http://blog.51cto.com/13407306/2056617,如需转载请自行联系原作者

优秀的个人博客,低调大师

MCollective架构篇2-MCollective+MQ架构的部署

零基础学习Puppet自动化配置管理系列文档 1 Mcollective介绍 MCollective 是一个构建服务器编排(Server Orchestration)和并行工作执行系统的框架。 首先,MCollective 是一种针对服务器集群进行可编程控制的系统管理解决方案。在这一点上,它的功能类似:Func,Fabric 和 Capistrano。 其次,MCollective 的设计打破基于中心存储式系统和像 SSH 这样的工具,不再仅仅痴迷于 SSH 的 For 循环。它使用发布订阅中间件(Publish Subscribe Middleware)这样的现代化 工具和通过目标数据(meta data)而不是主机名(hostnames)来实时发现网络资源这样的现代化理念。提供了一个可扩展的而且迅速的并行执行环境。 MCollective 工具为命令行界面,但它可与数千个应用实例进行通信,而且传输速度惊人。无论部署的实例位于什么位置,通信都能以线速进行传输,使用的是一个类似多路传送 的推送信息系统。MCollective 工具没有可视化用户界面,用户只能通过检索来获取需要应用的实例。Puppet Dashboard 提供有这部分功能。 2 安装和配置RabbitMQ 2.1 安装和配置RabbitMQ 2.1.1 安装RabbitMQ [root@puppetserverrpms]#yuminstallerlang#RabbitMQ依赖erlang语言,需要安装大概65个左右的erlang依赖包 [root@puppetserverrpms]#yuminstallrabbitmq-server [root@puppetserverrpms]#ll/usr/lib/rabbitmq/lib/rabbitmq_server-3.1.5/plugins/#默认已经安装了stomp插件,老版本需要下载安装 -rw-r--r--1rootroot242999Aug2417:42amqp_client-3.1.5.ez -rw-r--r--1rootroot85847Aug2417:42rabbitmq_stomp-3.1.5.ez … 2.1.2 启动rabbitmq-server [root@puppetserverrpms]#/etc/rc.d/init.d/rabbitmq-serverstart#启动rabbitmq服务 Startingrabbitmq-server:SUCCESS rabbitmq-server. [root@puppetserverrpms]#/etc/rc.d/init.d/rabbitmq-serverstatus#查看rabbitmq状态 Statusofnoderabbit@puppetserver... [{pid,43198}, {running_applications,[{rabbit,"RabbitMQ","3.1.5"}, {mnesia,"MNESIACXC13812","4.5"}, {os_mon,"CPOCXC13846","2.2.7"}, {xmerl,"XMLparser","1.2.10"}, {sasl,"SASLCXC13811","2.1.10"}, {stdlib,"ERTSCXC13810","1.17.5"}, {kernel,"ERTSCXC13810","2.14.5"}]}, {os,{unix,linux}}, {erlang_version,"ErlangR14B04(erts-5.8.5)[source][64-bit][rq:1][async-threads:30][kernel-poll:true]\n"}, {memory,[{total,27101856}, {connection_procs,2648}, {queue_procs,5296}, {plugins,0}, {other_proc,9182320}, {mnesia,57456}, {mgmt_db,0}, {msg_index,21848}, {other_ets,765504}, {binary,3296}, {code,14419185}, {atom,1354457}, {other_system,1289846}]}, {vm_memory_high_watermark,0.4}, {vm_memory_limit,838362726}, {disk_free_limit,1000000000}, {disk_free,15992676352}, {file_descriptors,[{total_limit,924}, {total_used,3}, {sockets_limit,829}, {sockets_used,1}]}, {processes,[{limit,1048576},{used,122}]}, {run_queue,0}, {uptime,4}] ...done. [root@puppetserverrpms]#netstat-nlp|grepbeam#默认监听端口为5672 tcp000.0.0.0:444220.0.0.0:*LISTEN43198/beam tcp00:::5672:::*LISTEN43198/beam 2.1.3 配置RabbitMQ 2.1.3.1 加载amqp_client和rabbit_stomp插件 [root@puppetserversbin]#ln-s/usr/lib/rabbitmq/lib/rabbitmq_server-3.1.5/sbin/rabbitmq-plugins/usr/sbin/rabbitmq-plugins#创建命令rabbitmq-plugins的软连接 [root@puppetserversbin]#ln-s/usr/lib/rabbitmq/lib/rabbitmq_server-3.1.5/sbin/rabbitmq-env/usr/sbin/rabbitmq-env#创建命令rabbitmq-env的软连接 [root@puppetserversbin]#rabbitmq-pluginsenablerabbitmq_stomp#开启rabbitmq_stomp插件 Thefollowingpluginshavebeenenabled: amqp_client rabbitmq_stomp Pluginconfigurationhaschanged.RestartRabbitMQforchangestotakeeffect. [root@puppetserversbin]#/etc/rc.d/init.d/rabbitmq-serverrestart Restartingrabbitmq-server:SUCCESS rabbitmq-server. [root@puppetserverrabbitmq]#tailf/var/log/rabbitmq/rabbit\@puppetserver.log#可以从日志看到stomp插件加载成功 =INFOREPORT====3-Oct-2013::20:25:18=== startedSTOMPTCPListeneron[::]:61613 =INFOREPORT====3-Oct-2013::20:25:18=== Serverstartupcomplete;2pluginsstarted. *amqp_client *rabbitmq_stomp 2.1.3.2 创建rabbitmq.config配置文件,修改监听端口为61613 [root@puppetserver rpms]# vim /etc/rabbitmq/rabbitmq.config [ {stomp,[{tcp_listeners,[61613]}]}#设置connector为stomp,监听端口为61613 ]. [root@puppetserver rpms]# /etc/rc.d/init.d/rabbitmq-server restart Restarting rabbitmq-server: SUCCESS rabbitmq-server. [root@puppetserver rpms]# netstat -nlp | grep beam #默认监听端口为61613 tcp 0 0 0.0.0.0:56532 0.0.0.0: LISTEN 1906/beam.smp tcp 0 0 :::61613 ::: LISTEN 1906/beam.smp tcp 0 0 :::5672 :::* LISTEN 1906/beam.smp 2.1.3.3 删除默认账户guest,为MCollective创建账户“mcollective”并设置密码为“secret”,然后设置权限。 [root@puppetserverrpms]#rabbitmqctldelete_userguest Deletinguser"guest"... ...done. [root@puppetserverrpms]#rabbitmqctladd_usermcollectivesecret Creatinguser"mcollective"... ...done. [root@puppetserverrpms]#rabbitmqctlset_permissions-p"/"mcollective".*"".*"".*" Settingpermissionsforuser"mcollective"invhost"/"... ...done. [root@puppetserversbin]#rabbitmqctllist_users#查看监听用户 Listingusers... mcollective[] ...done. 备注:RabbitMQ拥有一个默认的guest账户,它默认对消息队列拥有全部权限。出于安全方面的考虑,建议删除这个账户。 更多详细配置信息请参考http://www.rabbitmq.com/admin-guide.html 更多详细配置信息请参考:http://docs.puppetlabs.com/mcollective/reference/plugins/connector_rabbitmq.html 3 安装和配置MCollective 3.1 安装MCollective 3.1.1 测试端安装MCollective客户端 [root@puppetserverrpms]#yuminstallmcollective-commonmcollective-client#依赖包rubygem-stomp 3.1.2 节点安装MCollective服务端 [root@agent1~]#yuminstallmcollectivemcollective-common#依赖rubygem-stomp、rubygems和ruby相关包 3.2 配置MCollective 3.2.1 测试端配置MCollective客户端 [root@puppetserverrpms]#vim/etc/mcollective/client.cfg topicprefix=/topic/ main_collective=mcollective collectives=mcollective libdir=/usr/libexec/mcollective logger_type=console loglevel=warn #Plugins securityprovider=psk plugin.psk=a36cd839414370e10fd281b8a38a4f48#MCollective通信共享密钥,和MCollective服务端保持一致 connector=stomp#通信协议 plugin.stomp.host=192.168.100.110#Middleware地址 plugin.stomp.port=61613#Middleware监听端口 plugin.stomp.user=mcollective#Middleware通信账号 plugin.stomp.password=secret#Middleware通信密码 #Facts factsource=yaml plugin.yaml=/etc/mcollective/facts.yaml 3.2.2 节点配置MCollective服务端 [root@agent1rpms]#vim/etc/mcollective/server.cfg topicprefix=/topic/ main_collective=mcollective collectives=mcollective libdir=/usr/libexec/mcollective#存放plugins的位置 logfile=/var/log/mcollective.log loglevel=info daemonize=1 #Plugins securityprovider=psk plugin.psk=a36cd839414370e10fd281b8a38a4f48#MCollective通信共享密钥,和MCollective客户端保持一致 connector=stomp#通信协议 plugin.stomp.host=192.168.100.110#Middleware地址 plugin.stomp.port=61613#Middleware监听端口 plugin.stomp.user=mcollective#Middleware通信账号 plugin.stomp.password=secret#Middleware通信密码 #Facts factsource=yaml plugin.yaml=/etc/mcollective/facts.yaml [root@agent1~]#/etc/rc.d/init.d/mcollectivestart Startingmcollective:[OK] [root@agent1~]#chkconfigmcollectiveon [root@agent1~]# 3.3 测试Mcollective与Middleware通信 [root@puppetserverrpms]#mcoping#检查所有存活的节点 agent2.kisspuppet.comtime=119.98ms agent1.kisspuppet.comtime=159.31ms ----pingstatistics---- 2repliesmax:159.31min:119.98avg:139.64 [root@puppetserverrpms]#mcofind agent1.kisspuppet.com agent2.kisspuppet.com 本文转自凌激冰51CTO博客,原文链接:http://blog.51cto.com/dreamfire/1566372,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册