C++ 微服务 UserServer 设计与实战落地
做 IM 项目时,用户服务(UserServer)是整个系统的基石 —— 所有业务(好友、消息、朋友圈)都依赖用户认证和基础信息。这篇文章就从实战角度,聊聊我是怎么设计、实现 UserServer 的,包括核心功能落地、依赖替换(比如用模拟短信服务替代真实平台),以及那些踩过的坑。
UserServer 在 IM 系统中的定位
在之前的 IM 微服务架构里,UserServer 承担 3 个核心职责:
- 用户认证:注册(用户名 / 手机号)、登录(用户名密码 / 手机验证码)、会话管理;
- 用户信息管理:头像、昵称、签名、手机号的修改与查询;
- 基础支撑:给其他服务提供用户信息(比如好友服务查好友资料、消息服务查发送者信息)。
所以设计时,必须考虑可扩展性(比如后续加第三方登录)、可测试性(比如不用真实短信也能测手机号登录)、性能(登录会话用 Redis 缓存,避免查库)。
核心设计:从依赖到架构,拒绝'硬编码'
依赖注入:让服务更灵活
最开始写 UserServiceImpl 的时候,我直接在类里 new 了 DMSClient(真实短信服务),后来发现个人开发者没法申请企业短信资质,想换成模拟服务时,改了大半天代码。后来重构时,把所有外部依赖都通过构造函数注入,这才清爽了。
看核心构造函数:
UserServiceImpl(const MockSmsClient::ptr& mock_sms_client, // 短信服务(真实/模拟可替换)
const std::shared_ptr<elasticlient::Client>& es_client, // ES(用户搜索用)
const std::shared_ptr<odb::core::database>& mysql_client, // MySQL(用户数据存储)
const std::shared_ptr<sw::redis::Redis>& redis_client, // Redis(会话/验证码)
const ServiceManager::ptr& channel_manager, // 服务管理(调用文件服务等)
const std::string& file_service_name) // 文件服务名称(定位服务用)
: _es_user(std::make_shared<ESUser>(es_client)),
_mysql_user(std::make_shared<UserTable>(mysql_client)),
_redis_session(std::make_shared<Session>(redis_client)),
_redis_status(std::make_shared<Status>(redis_client)),
_redis_codes(std::make_shared<Codes>(redis_client)),
_file_service_name(file_service_name),
_mm_channels(channel_manager),
_dms_client(mock_sms_client) // 注入短信服务,而非内部 new
{
_es_user->();
}


