高可用的用户注册解决方案
「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战」
一、redis中的Hash结构
字典
- Redis 的字典底层实现是基于 Hash table, 一个Hash table 里面可以有多个哈希表节点,而每个哈希表节点保存了字典中的一个键值对。
- Redis 的 Hash 和 Java 的 HashMap的内部结构实现是一致,即数组+链表结构。只是 它们的 reHash 方式不一样。
ziplist算法
Redis hash在存储优化上Hash有优化算法,称为ziplist(Redis 2.6之前称为zipmap)。
该压缩算法能够优化节省内存,ziplist也用于优化排序set和list集合的存储。当一个hash压偏到这样一个压缩过的集合中时,类似这样排列:
[key1, value1, key2, value2, ...]
带有一些key的Hash能够被打包进入线性数组结构,同时保证get和set时的O(1)性能。
这种方式不会随着hash字段增加时能够保持保证get和set时的O(1)性能,当hash增长时,它会被转为标准的字典结构来维持O(1)性能,而空间节省特性就会失效,Redis配置参数会控制这个转换:
- list-max-ziplist-entries :默认 (512): 如果hash增长大于这个限制值,将改变到标准模式(字典)
- list-max-ziplist-value :默认 (64): 当hash中最大元素超过这个限制值,将改变到标准模式(字典)
为了节约内存,推荐使用hash替代普通字符串的使用,这就能利用Redis强大的hash特性,因此,请尽可能使用hash,小的hash将被编码使用小的空间,
Redis Hash自然适合存储这些对象:会话session, 用户信息、商品信息、配置信息等,同时这也是缓存大量数据的选择。
二、redis中的String和Hash区别
String 适合存储用户信息,而 Hash 结构也可以存储用户信息,不过是对每个字段单独存储,因此可以在查询时获取部分字段的信息,节省网络流量。
- 适合用 String 存储的情况:
- 每次需要访问大量的字段
- 存储的结构具有多层嵌套的时候
- 适合用 Hash 存储的情况:
- 存储海量缓存信息,使用hash结构使用内存比string结构少
- 在大多数情况中只需要访问少量字段
- 自己始终知道哪些字段可用,防止使用 mget 时获取不到想要的数据
- 储存java bean对象业务剖析
三、注册微博的redis技术方案
注:每个hash可以存储2的(32-1)方的键值对(40多亿)
四、SpringBoot+Redis 实现微博注册
步骤1:创建user表
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL DEFAULT '' COMMENT '用户名',
`password` varchar(50) NOT NULL DEFAULT '' COMMENT '密码',
`sex` tinyint(4) NOT NULL DEFAULT '0' COMMENT '性别 0=女 1=男 ',
`deleted` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '删除标志,默认0不删除,1删除',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户表';
SET FOREIGN_KEY_CHECKS = 1;
复制代码
步骤2:注册逻辑
@Api(description = "用户接口")
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@ApiOperation(value="微博注册")
@PostMapping(value = "/createUser")
public void createUser(@RequestBody UserVO userVO) {
User user=new User();
BeanUtils.copyProperties(userVO,user);
//注册
userService.createUser(user);
}
}
复制代码
/**
* 微博注册
*/
public void createUser(User obj) {
//步骤1:先入库
this.userMapper.insertSelective(obj);
//步骤2:入库成功后,写入redis
obj = this.userMapper.selectByPrimaryKey(obj.getId());
//将Object对象里面的属性和值转化成Map对象
Map<String, Object> map = ObjectUtil.objectToMap(obj);
//设置缓存key
String key = Constants.CACHE_KEY_USER + obj.getId();
//微博用户的存储采用reids的hash
HashOperations<String, String, Object> opsForHash = redisTemplate.opsForHash();
opsForHash.putAll(key, map);
//步骤3:设置过期30天
this.redisTemplate.expire(key, 30, TimeUnit.DAYS);
}
复制代码
注:这里探讨redis的hash结构的使用场景,至于高可用高并发的代码并没有仔细考虑,大家可以用lua脚本代替多次redis网络请求等。。。
redis分布式缓存系列
- redis分布式缓存(一)一一 redis安装(linux和docker)
- redis分布式缓存(二)一一 RDB和AOF
- redis分布式缓存(三)一一 SpringBoot集成Mybatis-Plus,Redis和Swagger
- redis分布式缓存(四)一一 SpringCache集成Redis
- redis分布式缓存(五)一一 常用命令(String)
- redis分布式缓存(六)一一 文章的阅读量PV解决方案
- redis分布式缓存(七)一一 分布式全局id解决方案
- redis分布式缓存(八)一一 高并发原子性操作(Redis+Lua)
- redis分布式缓存(九)一一 黑客防刷攻击解决方案
- redis分布式缓存(十)一一 常用命令(Hash)
- redis分布式缓存(十一)一一 储存java bean对象业务剖析
- redis分布式缓存(十二)一一 短链接解决方案
- redis分布式缓存(十三)一一 京东购物车解决方案
- redis分布式缓存(十四)一一 分布式session不一致性解决方案
- 文章持续更新中...




近期评论