1. 项目概述
最近在重构公司老旧的单体通讯系统,决定采用微服务架构实现一个高可用的即时通讯平台。作为系列的第二篇,今天重点分享服务端环境搭建的完整过程。不同于简单的Spring Boot单体应用,微服务架构下的环境配置需要考虑服务注册发现、配置中心、API网关等核心组件的协同工作。
我选择了Spring Cloud Alibaba作为技术栈,主要基于以下考量:
- Nacos同时具备服务注册中心和配置中心功能,比Eureka+Config组合更轻量
- Sentinel在流量控制方面比Hystrix更灵活
- Dubbo在RPC性能上优于Feign
- 社区活跃度高,中文文档齐全
这套组合在电商、社交等领域已有大量成功案例,特别适合需要处理高并发消息的IM系统。下面就从最基础的环境准备开始,手把手带你搭建一个可横向扩展的微服务通讯后端。
2. 基础环境准备
2.1 开发工具选型
工欲善其事必先利其器,经过多轮对比测试,最终环境配置如下:
| 工具 | 版本 | 备注 |
|---|---|---|
| JDK | 17 | 选择LTS版本,ZGC垃圾回收器表现优异 |
| IntelliJ IDEA | 2023.1 | 终极版支持Spring Cloud全系插件 |
| Maven | 3.8.6 | 需要配置阿里云镜像加速依赖下载 |
| Docker Desktop | 4.16.2 | 容器化部署必备 |
| MySQL | 8.0.32 | 使用Group Replication方案 |
| Redis | 7.0.11 | 消息缓存与分布式锁核心组件 |
重要提示:JDK务必选择17而非最新版本,实测在Netty堆外内存管理上更稳定。曾用JDK20遇到DirectBuffer内存泄漏问题,回退后解决。
2.2 本地开发环境配置
- Maven settings.xml配置:
xml复制<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
- IDEA必备插件:
- Lombok:自动生成getter/setter
- Arthas Idea:在线诊断工具集成
- Alibaba Java Coding Guidelines:代码规范检查
- Grep Console:日志着色显示
- Hosts文件添加:
code复制127.0.0.1 im-nacos
127.0.0.1 im-mysql
127.0.0.1 im-redis
这样在代码中可以用域名代替IP,方便后续迁移到正式环境。
3. 核心组件部署
3.1 Nacos集群搭建
采用Docker Compose部署3节点集群,docker-compose-nacos.yml关键配置:
yaml复制services:
nacos1:
image: nacos/nacos-server:v2.2.3
environment:
- MODE=cluster
- NACOS_SERVERS=nacos1:8848 nacos2:8848 nacos3:8848
- SPRING_DATASOURCE_PLATFORM=mysql
- MYSQL_SERVICE_HOST=im-mysql
- MYSQL_SERVICE_DB_NAME=im_nacos
- MYSQL_SERVICE_USER=nacos
- MYSQL_SERVICE_PASSWORD=nacos@123
ports:
- "8848:8848"
- "9848:9848"
启动后需要初始化数据库,执行nacos-mysql.sql脚本。特别注意:
- 9848端口用于Raft协议通信,必须开放
- 生产环境需要配置鉴权参数NACOS_AUTH_ENABLE=true
- JVM参数建议调整:-Xms2g -Xmx2g -Xmn1g
3.2 MySQL集群配置
使用Group Replication方案,关键配置my.cnf:
ini复制[mysqld]
server_id = 1
gtid_mode = ON
enforce_gtid_consistency = ON
binlog_checksum = NONE
log_slave_updates = ON
binlog_format = ROW
transaction_write_set_extraction = XXHASH64
loose-group_replication_group_name = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
loose-group_replication_start_on_boot = OFF
loose-group_replication_local_address = "im-mysql1:33061"
loose-group_replication_group_seeds = "im-mysql1:33061,im-mysql2:33061,im-mysql3:33061"
loose-group_replication_bootstrap_group = OFF
踩坑记录:曾经直接使用主从复制,在消息已读状态同步时出现数据不一致,改用Group Replication后解决。
3.3 Redis哨兵部署
配置sentinel.conf核心参数:
conf复制sentinel monitor im-redis-master im-redis1 6379 2
sentinel down-after-milliseconds im-redis-master 5000
sentinel failover-timeout im-redis-master 60000
sentinel parallel-syncs im-redis-master 1
Spring Boot连接配置示例:
properties复制spring.redis.sentinel.master=im-redis-master
spring.redis.sentinel.nodes=im-redis1:26379,im-redis2:26379,im-redis3:26379
spring.redis.password=your_strong_password
4. 微服务脚手架搭建
4.1 父工程配置
pom.xml关键依赖管理:
xml复制<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2022.0.0.0-RC2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
4.2 通用模块设计
创建im-common模块包含:
- 统一返回体:Result
封装 - 异常处理:@RestControllerAdvice全局捕获
- 工具类:
- SnowflakeIdWorker 分布式ID生成
- JwtUtils Token处理
- RedisDistributedLock 基于Lua脚本实现
- 常量定义:消息类型、状态码等
4.3 服务发现配置
所有子模块需添加bootstrap.yml:
yaml复制spring:
application:
name: im-user-service
cloud:
nacos:
discovery:
server-addr: im-nacos:8848
namespace: dev
group: IM_GROUP
config:
file-extension: yaml
shared-configs:
- data-id: im-common.yaml
group: IM_GROUP
refresh: true
5. 核心问题排查实录
5.1 服务注册失败排查
现象:服务启动后未出现在Nacos服务列表
排查步骤:
- 检查bootstrap.yml是否在resources目录
- 确认namespace存在且拼写正确
- 查看日志是否有"Registering service..."字样
- 用tcpdump抓包分析8848端口通信
最终发现:项目依赖了spring-cloud-starter-bootstrap但未显式引入,导致bootstrap.yml未加载
5.2 Redis连接池爆满
现象:频繁报Cannot get Jedis connection
解决方案:
yaml复制spring.redis.lettuce.pool:
max-active: 16
max-wait: 1000
max-idle: 8
min-idle: 4
timeout: 2000
配合Arthas监控连接数:
bash复制watch org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider getConnection '{params,returnObj,throwExp}' -n 5 -x 3
5.3 分布式事务处理
消息已读状态需要跨用户服务和消息服务更新,采用Seata方案:
- 安装Seata Server:
bash复制docker run --name seata-server -p 8091:8091 -e SEATA_IP=your_ip seataio/seata-server:1.6.1
- 配置undo_log表:
sql复制CREATE TABLE `undo_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
- 业务方法添加注解:
java复制@GlobalTransactional
public void markAsRead(Long messageId) {
// 业务逻辑
}
6. 性能优化实践
6.1 JVM参数调优
在application.yml中添加:
yaml复制spring:
application:
name: im-gateway
cloud:
gateway:
httpclient:
pool:
type: ELASTIC
max-connections: 1000
acquire-timeout: 2000
配合启动参数:
bash复制java -jar -Xms2g -Xmx2g -XX:+UseZGC -XX:MaxGCPauseMillis=100 -Xlog:gc*=debug:file=gc.log im-gateway.jar
6.2 消息存储设计
采用冷热分离架构:
- 热数据:Redis Sorted Set存储最近7天消息
- 冷数据:MongoDB分片集群存储历史消息
消息表设计关键字段:
sql复制CREATE TABLE `im_message` (
`id` BIGINT PRIMARY KEY COMMENT '雪花ID',
`conversation_id` VARCHAR(64) NOT NULL COMMENT '会话ID',
`from_uid` BIGINT NOT NULL COMMENT '发送者',
`to_uid` BIGINT NOT NULL COMMENT '接收者',
`content` TEXT NOT NULL COMMENT '消息内容',
`content_type` TINYINT NOT NULL COMMENT '1文本 2图片 3语音',
`status` TINYINT DEFAULT 0 COMMENT '0未读 1已读 2撤回',
`created_at` DATETIME(3) NOT NULL COMMENT '精确到毫秒',
INDEX `idx_conversation` (`conversation_id`),
INDEX `idx_to_uid_status` (`to_uid`, `status`)
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;
6.3 连接池监控
通过Micrometer暴露指标:
java复制@Bean
public MeterRegistryCustomizer<PrometheusMeterRegistry> redisMetrics() {
return registry -> registry.config().commonTags("application", "im-service");
}
Grafana监控看板配置关键指标:
- redis.connections.active
- redis.connections.idle
- redis.connections.max
- redis.connections.min
这套环境搭建方案已在生产环境稳定运行半年,支撑日均千万级消息处理。后续会继续分享消息推送、分布式会话管理等核心模块的实现细节。
