首页
归档
朋友
关于我
留言
Search
1
虚拟机无法ping不通百度,并无法访问浏览器
4,847 阅读
2
mysql使用or条件使索引失效
4,061 阅读
3
mysql如何在一对多查询时选取时间最近的一条记录
3,475 阅读
4
根据MySQL获取当天,昨天,本周,本月,上周,上月,本月的起始时间
2,927 阅读
5
熟悉mysql的共享锁、排它锁、悲观锁、乐观锁以及使用场景
1,766 阅读
PHP
面向对象
设计模式
知识汇总
常用函数
PHP框架知识
数据库
MySQL
服务器
Docker
虚拟机
Nginx
缓存相关
Redis
前端
中间件
RabbitMQ
网络编程
HTTP相关
Swoole
Workerman
工具软件
Git
Typecho
杂乱无章
面试指南
PHP相关
MySQL面试汇总
中间件相关
开发技巧 | 优化
登录
Search
标签搜索
php
mysql
代码片段
linux
Thinkphp
Redis
nginx
mysql优化
docker
面试指南
面向对象
git
Laravel框架
http协议
RabbitMQ
Redis性能优化
设计模式
linux命令
编译安装
PhpSpreadsheet
黎明强
累计撰写
70
篇文章
累计收到
59
条评论
首页
栏目
PHP
面向对象
设计模式
知识汇总
常用函数
PHP框架知识
数据库
MySQL
服务器
Docker
虚拟机
Nginx
缓存相关
Redis
前端
中间件
RabbitMQ
网络编程
HTTP相关
Swoole
Workerman
工具软件
Git
Typecho
杂乱无章
面试指南
PHP相关
MySQL面试汇总
中间件相关
开发技巧 | 优化
页面
归档
朋友
关于我
留言
搜索到
5
篇与
Redis
的结果
2022-07-12
Redis的常用命令&集群节点管理
基本操作切换某个库 (默认有0~15个库)select [number]查看某个key所占的字节数memory usage key删除某个keydel key #阻塞删除key unlink key #异步非阻塞删除获取所有的keykeys * #慢,大量缓存不建议这样遍历查询 scan 0 match * count 10000 #快,游标式的遍历单节点模式下客户端访问redis-cli -a [密码] -h [IP] -p [端口]集群模式下 客户端访问redis-cli -a [密码] -c -h [IP] -p [端口]基本类型操作字符串(string)添加一条String类型数据set key value添加一条String类型数据mset key1 value1 key2 value2获取某个字符串key的值get key自增(默认 +1)incr key number自增(默认-1)decr key number删除keydel key 哈希(hash)设置属性 (可设置多个key value)hset keyname field1 value1 field2 value2获取某个属性值hget keyname filed获取key的多个字段hmget keyname field1 field2 获取key的所有字段hgetall keyname hash中进行自增、自减hincrby keyname filed 10 #增长 hdecrby keyname filed 10 #减少列表(List)左进lpush key value1 value2 value3左出lpop key右进rpush key value1 value2 value3右出rpop key查看范围rlange key cursor number集合(Set)添加内容sadd key value1 value2查询key里所有的值smembers key移除key里面的某个valuesrem key value随机移除某个valuespop key 判断这个集合里是否有该成员SISMEMBER key "string"返回两个set的并集sunion key1 key2返回key1剔除交集的那部分(差集)sdiff key1 key2跟siffer相反,返回交集sinter key1 key2 有序集合(Sorted sets)添加元素zadd key score value [score value..]获取key的长度zcard key获取集合的值并按照score排序 ( 最小的是最上面)zrange key start end # 排序小到大 zrevrange key start end # 排序大到小为key中某个值增加 socre分zincrby key score value 删除key中的某个值zrem key value根据key中的某个value值 ,返回scorezscore key value移除有序集 key 中,指定排名(rank)区间内的所有成员。【返回个数】zremrangebyrank key [start] [stop] 统计key中区间的值有几个元素(返回N个)zcount key [数值min] [数值max]根据value获取某个值的位置 【获取排序号,默认小到大】zrank key value # 默认小到大排序 zrevrank key value # 大到小排序根据score值获取区间的valuezrangebyscore key [score:min] [score:max] #小到大排序 zrangebyscore key [score:max] [score:min] #大到小排序返回有序集key中,所有score值介于min和max之间(包含等于min或max)的成员。有序集成员按score值递增(从小到大)次序排列,最小的是最上面zrangebyscore key [数值min] [数值max]进阶类型操作BitMapsbitmaps 更多用法指定偏移量bit位置设置值SETBIT key offset value # SETBIT user:sign:98:202003 0 1 # 3月1号签到 # SETBIT user:sign:98:202003 2 1 # 3月3号签到 查询指定偏移位置的bit值GETBIT key offset # getbit user:sign:98:202003 2 #获取用户98的2020年3月3号的value ,0-未签到,1-签到统计指定字节区间bit为1的数量 (统计总签到次数)BITCOUNT key [start end] # bitcount user:sign:98:202003 #返回总数操作多字节位域 (获取当前月的所有签到数据 , 计算连续签到天数)BITFIELD key [get type offset] [set type offset value] [incrby type offset increment] [overflow wrap/set/fail] # bitfield user:sign:98:202203 get u3 0 # get u3 : 这个u 代表是要求无符号的类型去转进制, 3代表3个 #但是返回内容是 从二进制转成十进制。查询指定字节区间的第一个被设置成1的bit位的位置BITPOS key bit [start] [end]GEO用于地址位置,经纬度计算 ,更多例子添加地理位置GEOADD key longitude latitude member [longitude latitude mermber...] # GEOADD location 121.446617 31.205593 'zhangsan' # GEOADD location 121.4465774 31.20485103 'lisi' 121.44534 31.2031 'wangwu' 121.4510648 31.2090667 'zhangliu'两点间的距离GEODIST key member1 member2 [unit] # GEODIST location zhangsan lisi m "82.4241" # GEODIST location zhangsan lisi km "0.0824"返回标准的Geohash值GEOHASH key member [member] #geohash location zhangsan "wtw3e8f9z20"返回key中给定元素的位置信息(经纬度)GEOPOS key member [member ...] # GEOPOS location zhangsan 121.44661813974380493 31.20559220971455971 # GEOPOS location zhangsan lisi "121.44661813974380493 31.20559220971455971 121.44657522439956665 31.20485207113603821"返回以某点为圆心,距离为半径的其他位置元素GEODIUS key longitude latitude redius m\|km\|ft\|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] # georadius location 121.446617 31.205593 3000 m wangwu lisi zhangsan zhangliu # georadius location 121.446617 31.205593 3000 m WITHCOORD wangwu 121.44534140825271606 31.20310057881493293 lisi 121.44657522439956665 31.20485207113603821 zhangsan 121.44661813974380493 31.20559220971455971 zhangliu 121.45106524229049683 31.20906731242401833跟georedius一样,只不过圆心是给定的memeber元素GEODIUSBYMEMBER key longitude latitude redius m\|km\|ft\|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] # georadiusbymember location zhangsan 3000 m wangwu lisi zhangsan zhangliu # georadiusbymember location zhangsan 3000 m withcoord wangwu 121.44534140825271606 31.20310057881493293 lisi 121.44657522439956665 31.20485207113603821 zhangsan 121.44661813974380493 31.20559220971455971 zhangliu 121.45106524229049683 31.20906731242401833优化操作指令扫描bigkeyredis-cli --bigkeys获取慢查询日志slowlog get n 性能测试./redis-benchmark -a [密码] -h [Ip] -p [端口] -t [指令/命令] -r 100000 -n 1000000 -c 1000Redis信息查看Redis(集群、主从、节点)状态以及内存使用情况info replication Redis Cluster 集群查看集群信息客户端 查看节点信息redis-cli -a [登录密码] -c -h [IP地址] -p [端口] cluster nodes通过check 查看节点信息(列表)redis-cli -a [登录密码] --cluster check [IP+端口]管理节点集群 · 添加主节点redis-cli --cluster add-node new_host:new_port existing_host:existing_port --cluster-master-id node_idnew_host : new_port : 需要添加节点到集群的IP和端口existing_host : existing_port : 环境中最后存在的IP和端口 (最后是根据槽的位置判定的)node_id : 槽位的最后的主节点id集群 · 重新分片redis-cli --cluster reshard host:port --cluster-from node_id --cluster-to node_id --cluster-slots <args> --cluster-yeshost:port : 可写任意集群节点中的IP--cluster-from : 新节点从哪个节点上的槽-cluster-to : 分配给新节点上的槽--cluster-slots : 给多少个槽数 (如果有数据,数据也会一同过去)--cluster-yes : 回显槽的分配情况
2022年07月12日
298 阅读
0 评论
0 点赞
2022-06-18
Redis的性能优化一些方案
Redis性能优化客户端优化Pipeline批量操作连接池的应用设置合理的淘汰机制设置合理的内存大小设置合理的过期时间 (设置的太久,久而久之内存空间不够用了,设置的太短,key失效就会频繁的出现淘汰策略)选择合适的淘汰策略key与value的优化Key设计可读性和可管理性,以业务名(或数据库名)为前缀(防止key冲突),用冒号分隔,比如 业务名:表:id简洁性,保证语义的前提下,控制key的长度,当key较多时,内存占有也不容忽视不要包含特殊字符,比如:包含空格、换行、单双引号以及其他转义字符Value设计拒绝Bigkey(防止网卡流量、慢查询),string类型控制在10kb以内,hash、list、set、zset元素个数不要超过5000。选择合适的数据类型控制key的生命周期(设置有效时间),redis不是垃圾桶BigKey的优化什么样的Key才算是Big Key呢?一般情况下,当key的值大于10Kb时就可以算是Big Key了。如下场景都是可能遇到Big key,比如:粉丝列表统计数据,比如PV或者UV统计使用不当的数据缓存,比如通过String保存序列化后的用户数据等出现了Big Key你也不用非常紧张,因为某些场景下不得不使用,下面我们看下如何进行发现与优化发现Big Key常规做法:redis-cli-bigkeys优点:简单的扫描,不阻塞服务缺点:信息量太少了 (只能看到元素的个数)客户端访问cli#无密码 ./redis-cli --bigkeys #有密码 ./redis-cli -a 123456 --bigkeys会返回两部分的内容,分别是: 上半部分的“扫描部分” 下面的是“统计部分”。扫描区:会扫描当前redis最大的Key,(注意:但是并不代表它就是BigKey) ,只是告诉你当前环境最大的Key是比较大的。比如上面的user:sign:202206 占了1个字节 。Redis4.0之后的memory usage命令 memory usage 给出一个key和它值在RAM中占有的字节数,返回的结果是key的值以及为管理该key分配的内存总字节数。所以查询Big key的手段就可以使用脚本进行查询,大概思路就是时使用scan游标查询key,然后使用memeory usage key 获取这个key与value的字节数,这样就能很方便的得出结论进行优化,比如:import sys import redis def check_big_key(r,k); bigKey = False length = 0 try: type = r.type(k) if type == "string" length = r.strlen(k) elif type == "hash" length = r.hlen(k) elif type == "list" length = r.llen(k) elif type == "set" length = r.scard(k) elif type == "zset" length = r.zcard(k) except: retrun if length > 10240 : bigKey = True if bigKey : print db,k,type,length def find_big_key_normal(db_host,db_port,db_password,db_num) : r= redis.StrictRedis(host=db_host,port=db_port,password=db_password,db=db_num) for k in r.scan_iter(count=1000) : check_big_key(r,k) def find_log_key_sharding(db_host,db_port,db_password,db_num,nodecount) : r= redis.StrictRedis(host=db_host,port=db_port,password=db_password,db=db_num) cursor = 0 for node in range(0,nodecount) : while True : iscan = r.execute_command("iscan",str(node) , str(cursor) , "count" , "1000") for k in iscan[1] : check_big_key(r,k) cursos = iscan[0] print cursor,db,node, len(iscan[1]) if cursor == "0" : break; if __name__ "__main__" : if len(sys.argv) != 4 : print `Usage: python` , sys.argv[0] . "host port password" exit(1) db_host = sys.argv[1] db_port = sys.argv[2] db_password = sys.argv[3] r = redis.StrictRedi(host=db_host,port=int(db_port), password=db_password) nodecount = r.info()["nodecount"] keyspace_info = r.info("keyspace") for db in keyspace_info : print 'check', db , ' ' , keyspace_info[db] if nodecount > 1: find_log_key_sharding(db_host,db_port,db_password,db.replace("db",""), nodecount) else find_big_key_normal(db_host,db_port,db_password,db.replace("db","")) 可以通过python find_bigkey host 6379 password来执行,默认大key的阈值为10240(10kB) ,也就是对于string类型的value大于10240的认为是大Key,对于List的话如果list长度大于10240认为是大Key,对于hash的话,如果field的数目大于10240认为是大Key。另外默认该脚本每次搜索1000个key,对业务的影响比较低,不过最好在业务的低峰期进行操作,避免scan命令对业务的影响。删除Big KeyRedis4.0 新特性 - Lazy Free当删除键的时候,redis提供异步延迟释放key内存的功能,把key释放操作放在bio(Background I/O) 单独的子线程处理中,减少删除big key对redis主线程的阻塞。有效地避免删除big key带来的性能问题和可用性问题。因此删除big key时使用unlink 指令操作。使用del 指令去删除Big key会影响到主线程的操作,甚至带来阻塞线程(因为本来redis就是单线程的模型)。#慢 del user:1000 #快 (异步开启一个线程去执行) unlink user:1000Redis4.0之前对于string,还是用del指令删除 (一般来说,对于string类型使用del指令不会产生阻塞,影响不大 )对于hash、list、set、zset 等操作,使用hscan、ltrim、sscan、zscan 指令完成。禁止使用耗时操作指令禁止使用keys 命令,因为这个命令会遍历所以Key ,比较耗时。(使用scan 命令进行分批的,游标式的遍历) ;删除(del)一个大数据的时候,可以会需要很长时间,所以建议用异步的方式unlink ,它会启动一个新的线程来删除目标数据,而不是阻塞Redis的主线程。#慢 key * #快 scan 0 match * count 10000 scan 0 match user_* count 10000使用slowlog优化耗时指令 我们可以使用slowlog 功能找出最耗时的Redis命令进行相关优化,以提升Redis的运行速度,慢查询有两个重要的配置项:slowlog-log-slower-than 1000 : 用于设置慢查询的评定时间,也就是说超过此配置项的命令,就会被当做慢操作记录在慢查询日志中,它执行单位是微秒(1秒等于1000000微秒)。slowlog-max-len : 用来配置慢查询日志的最大记录数使用slowlog get n 来获取相关的慢查询日志,再找这些慢查询对应的业务进行相关的优化。系统存在的问题
2022年06月18日
369 阅读
0 评论
0 点赞
2022-06-18
Redis缓存的概念以及缓存异常处理
缓存的概念缓存是介入应用程序和物理数据之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高应用的运行性能。缓存内的数据对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻会同步缓存数据和物理数据源的数据。比如我们通常是直接查询MySQL数据库,那么在高并发情况下,大量查询MySQL数据库会导致数据库性能变慢。因此我们在应用层与MySQL之间搭建一个Cache层,让请求先访问Cache,这样能大大的降低数据库的压力,提高性能。分布式缓存简单来说,缓存系统能跨进程我们就称为分布式缓存在分布式系统开发中,系统与系统之间都是属于进程级别,缓存系统也能跨进程叫分布式缓存,市面上分布式技术有Memcached 和Redis 这两种,二者区别大致如下:性能Redis是单核的Memcahed是多核的内存空间和数据大小Memcached : 可以修改最大内存大小,进行LRU算法进行淘汰Redis : 不仅可以修改最大内存,因为redis的缓存是存储内存上的,一些数据可以通过VM的特性突破物理空间的限制。(可以理解:外挂一个磁盘当做数据存储源使用)操作比较Memcacehd : 操作比较单一,只有一种数据类型String,用来缓存。Redis : 支持比较丰富的数据类型,(String、哈希、集合、有序集合等),比如做一些签到、附近的人都可以(用bitmap、geo实现),减少服务端的操作,减少IO读写。可靠性Memcacehd :不支持持久化 ,断电重启数据就丢失,只能做缓存使用(需要重新从关系型数据库获取)Redis : 支持持久化 (RDB、AOF的2种机制) ,从持久化的数据磁盘加载并保存到缓存上,能处理单点故障、设置主从、集群、哨兵等机制。应用场景Memcacehd : 减轻数据库的压力,做缓存 (适合写少读多,或者纯读做缓存用的应用场景)Redis:也可以减少数据库的压力,做缓存,(对读多写多场景高 都适合),也可以实现比较复杂的业务实现(积分、签到、附近的人)谨慎考虑的部分Memcacehd :单个key-value的存储,value最大的上限是1M。只是内存缓存,对可靠性没太高要求。Reids :单String类型的key-value的存储,最大的上限是512M (42亿的字节)。Redis的可靠性强,可以理解内存性数据库。还有多个数据类型,一些高阶的数据类型,可以应付一些特殊的业务场景(签单存储bitMap , 附近的人Geo 、好友列表用Set)存储方式使用Redis做缓存的话,数据的存储结构有两种,一种采用String存储,另外使用Hashes 存储。那使用哪种更好呢?得具体情况具体分析:String 存储比较简单,固定的数据,比如存储一个简单的用户信息(用户名、昵称、头像、年龄等)。 存储时需要将数据进行序列化,获取时需要反序列化 , 在数据比较小的情况下还是可以忽略这种开销的。但如果存储的数据可能某些属性会有些变化,比如餐厅数据中,他有likeVotes(喜欢) 、 dislikeVotes(不喜欢)的数量,这类型的数据,那么我们采用Hashes 会更好,而且存储的时候没有序列化开销。官方推荐使用Hashes缓存异常解决如果缓存(异常)清空了,或者时间失效设计的不合理导致缓存删除,一下子突然千万用户访问进来导致数据库崩溃(应用宕机)缓存常见的三大经典问题:缓存击穿、缓存穿透、缓存雪崩缓存击穿原因存中的某个热点数据过期了,此时大量的请求访问了该热点数据,就无法从缓存中读取,直接访问数据库,数据库很容易就被高并发的请求冲垮,这就是缓存击穿的问题。解决方法:永不过期逻辑过期服务降级缓存穿透原因当用户访问的数据,既不在缓存中,也不在数据库中,导致请求在访问缓存时,发现缓存缺失,再去访问数据库时,发现数据库中也没有要访问的数据,没办法构建缓存数据,来服务后续的请求。那么当有大量这样的请求到来时,数据库的压力骤增,这就是缓存穿透的问题。就是明知道这个Key不在缓存,也不在数据库里,请求大量的这种导致数据库压力剧增。解决布隆过滤器空值存储 (上面有说)互斥锁 (不推荐 , 拿到锁请求数据库,没拿到锁就等待阻塞,只要用到锁 用不好锁必然会降低性能损耗)异步更新服务降级缓存雪崩原因:当大量缓存数据在同一时间过期(失效) 或者 Redis 故障宕机 时,如果此时有大量的用户请求,都无法在 Redis 中处理,于是全部请求都直接访问数据库,从而导致数据库的压力骤增,严重的会造成数据库宕机,从而形成一系列连锁反应,造成整个系统崩溃,这就是缓存雪崩的问题。解决随机失效时间双缓存 (用的不多,备份缓存,主数据失效了,那么去加载副的)互斥锁 (不推荐)服务降级其实最致命的是Redis节点故障,如果那个节点出问题访问不了缓存,那么数据的请求全怼在数据库里,造成数据库崩溃。解决方法:配置主从,集群、开启哨兵机制(防止某个节点宕机,如果某个节点宕机,就自动切换其他节点)缓存淘汰最大内存参数我们的redis数据库最大缓存、主键失效、淘汰机制等参数都是可以通过配置文件来配置的。这个文件是我们的redis.conf 文件。maxmemory <bytes> : 设置最大内存 #比如 maxmemory 500mb超过最大的内存,就会采用内存淘汰策略,执行淘汰,如下。内存淘汰策略截止目前redis一共为我们提供了八个不同的内存置换策略,很早之前提供了6种。# volatile-lru -> Evict using approximated LRU, only keys with an expire set. # allkeys-lru -> Evict any key using approximated LRU. # volatile-lfu -> Evict using approximated LFU, only keys with an expire set. # allkeys-lfu -> Evict any key using approximated LFU. # volatile-random -> Remove a random key having an expire set. # allkeys-random -> Remove a random key, any key. # volatile-ttl -> Remove the key with the nearest expire time (minor TTL) # noeviction -> Don't evict anything, just return an error on write operations. # # LRU means Least Recently Used # LFU means Least Frequently Used # # Both LRU, LFU and volatile-ttl are implemented using approximated # randomized algorithms. # # Note: with any of the above policies, Redis will return an error on write # operations, when there are no suitable keys for eviction. # # At the date of writing these commands are: set setnx setex append # incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd # sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby # zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby # getset mset msetnx exec sort # # The default is: # # maxmemory-policy noeviction默认不淘汰 , 开发中经常使用的是volatile-lruvolatile-lru:从已经设置过期时间的数据集中,挑选最近最少使用的数据淘汰。volatile-ttl:从已经设置过期时间的数据集中,挑选即将要过期的数据淘汰。volatile-random:从已经设置过期时间的数据集中,随机挑选数据淘汰。volatile-lfu:从已经设置过期时间的数据集中,会使用LFU算法选择设置了过期时间的键值对。allkeys-lru:从所有的数据集中,挑选最近最少使用的数据淘汰。allkeys-random:从所有的数据集中,随机挑选数据淘汰。no-enviction:禁止淘汰数据,如果redis写满了将不提供写请求,直接返回错误。注意这里的6种机制,volatile和allkeys规定了是对已设置过期时间的数据集淘汰数据还是从全部数据集淘汰数据,后面的lru、ttl以及random是三种不同的淘汰策略,再加上一种no-enviction永不回收的策略使用策略规则:如果数据呈现幂律分布,也就是一部分数据访问频率高,一部分数据访问频率低,则使用 allkeys-lru如果数据呈现平等分布,也就是所有的数据访问频率都相同,则使用 allkeys-random淘汰机制的实现既然是淘汰,那就需要把这些数据给删除,然后保存新的Redis删除策略主要有以下几种:惰性删除内存没满,则使用了这个,不额外开启一个线程去删除,就是保证高性能,在重新获取key的时候就知道这个key是否过期存在。定时删除每隔一段时间获取过期的key进行删除主动删除(内存满了,就主动删除多余的Key)
2022年06月18日
264 阅读
0 评论
0 点赞
2022-06-18
Redis使用Set集合实现好友功能(关注/互粉/共同好友等)
涉及的知识点:Redis的集合(Set) ( 也其实可以用有序集合存储)Redis Sets (集合)类型介绍集合类似Java中的HashSet,内部实现是一个value永远为null的HashMap,实际就是通过计算hash的方式来快速排重,这也是set能提供判断一个成员是否在集合内的原因。应用场景redis的sets类型是使用哈希表构造的,因此复杂度是O(1) ,它支持集合内的增删改查,并且支持多个集合间的交集、并集、差集操作。可以利用这些集合操作,解决程序开发过程当中很多数据集合间的问题。比如计算网络独立IP、用户画像中的用户标签、共同好友等功能。需求分析好友功能是目前社交场景的必备功能之一,一般好友相关功能包含有 :关注/取关 , 我(他)的关注, 我(他)的粉丝 ,共同关注 ,我关注的人也关注等这样一些功能。关系型数据库实现:用关系型数据库也可以实现,比如获取某个用户的粉丝,以及他关注的人。如果查询2个或者多个用户共同关注的人、 共同的粉丝 的查询非常麻烦,而且效率非常低。Reids实现:如果用Redis来实现是非常简单,用Redis的set(集合)去实现,而且效率也高。原因redis本身自带针对于交集并集差集的实现指令。不是把所有的数据都放入Redis里,整体的思路: 把落地持久化的数据保存在MySQL数据,把查询好友通过redis来实现。给每个用户都存储2个集合:一个是 关注集合(set)一个是 粉丝集合(set)比如,小明(我)关注了小红, 那么redis的存储是sadd following:小明 小红 #小明的关注表(set) sadd followers:小红 小明 #小红的粉丝列表 (set)作为自己,我关注了谁?作为被关注的人的时候,想知道谁关注了我 ,看到粉丝的情况。表结构CREATE TABLE `t_follow` ( `id` int NOT NULL AUTO_INCREMENT, `diner_id` int DEFAULT NULL COMMENT '用户id(我)', `follow_diner_id` int DEFAULT NULL COMMENT '用户id', `is_valid` tinyint(1) DEFAULT NULL COMMENT '关注状态(1-关注,0-取关)', `create_date` datetime DEFAULT NULL, `update_date` datetime DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE, KEY `index_followeddiner_valid` (`follow_diner_id`,`is_valid`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC OMMENT='关注表';;业务逻辑层大致流程查询库follow表:列表没数据,生成我关注的人数据 (Inster生成一条记录)列表有数据,状态=关注,再点就是取关的动作列表有数据,状态=取消关注,再点就是 重新关注。然后写入用set集合 写Redis中。Service代码层逻辑判断是否选择关注对象获取登录用户信息(token)获取当前登录用户与需要关注用户的关注信息如果没有关注信息,且要“关注”操作 ——添加关注 (inster)如果有关注信息,且目前处于关注状态,且要“取关”操作 , —— 取消关注 (update)如果有关注信息,且目前处于取关状态,且要“关注”操作 —— 重新关注 (upadte)返回处理具体不演示代码了。。逻辑一个意思。总结其实好友关注功能可以用set集合实现,也可以用sorted sets有序集合实现,方法都大同小异。一个是有根据权重可排名(实现先关注在前面,或者后关注在前面)。一个无规则排序。假设“我”的ID是1,“别人”的ID是2。添加关注添加关注分为两步:1、将对方id添加到自己的关注列表中;2、将自己的id添加到对方的粉丝列表中:SADD 1:follow 2 SADD 2:fans 1取消关注取消关注同样分为两步:1、将对方id从自己的关注列表中移除;2、将自己的id从对方的粉丝列表中移除:SREM 1:follow 2 SREM 2:fans 1关注列表查看我的关注列表SMEMBERS 1:follow # 查看别人的关注,把id换掉就可以粉丝列表查看我的粉丝列表SMEMBERS 2:fans # 查看别人的粉丝,把id换掉就可以我单向关注他我单向关注他,要同时满足两个条件:1、我的关注列表中有他(或他的粉丝列表中有我);2、我的粉丝列表中没有他(或他的关注列表中没有我)。SISMEMBER 1:follow 2 #true SISMEMBER 1:fans 2 #false他单向关注我他单向关注我,要同时满足两个条件:1、我的关注列表中没有他(或他的粉丝列表中没有我);2、我的粉丝列表中有他(或他的关注列表中有我)。SISMEMBER 1:follow 2 #false SISMEMBER 1:fans 2 #true我和某人是否互粉我和某人是否互粉,要同时满足两个条件:1、我的关注列表中有他(或他的粉丝列表中有我);2、我的粉丝列表中有他(或他的关注列表中有我)。同时成立才为互粉。SISMEMBER 1:follow 2 #true SISMEMBER 1:fans 2 #true互粉的关系是互相的,也可以反过来查。我的互粉查询和我互粉的人,实际是对我的关注和我的粉丝求交集SINTER 1:follow 1:fans共同关注查询1和2的共同关注,实际是1的关注和2的关注求交集SINTER 1:follow 2:follow我的关注数SCARD 1:follow我的粉丝数SCARD 1:fans其他问题目前存在的问题是,我的关注列表 & 我的粉丝列表,无法做到按关注时间排序,终端下显示是结果按ID正序排列的。考虑的解决方案是添加关注时同时存一份有序集合,关注时的时间戳是score。ZADD 1:follow 1457871625 2 ZADD 2:fans 1457871625 1那么我的关注列表是:ZREVRANGE 1:follow 0 -1同时,ZREVRANGE查询时的索引可以作为分页游标,基本解决目前的问题。使用有序集合实现总体思路我们采用redis里面的zset完成整个功能, 原因是zset有排序(我们要按照关注时间的倒序排列), 去重(我们不能多次关注同一用户)功能. 一个用户我们存贮两个集合 :一个是保存用户关注的人另一个是保存关注用户的人.用到的命令是:zadd 添加成员:命令格式: zadd key score member [score …]zrem 移除某个成员:命令格式: zrem key member [member ...]zcard 统计集合内的成员数:命令格式: zcard keyzrange 查询集合内的成员:命令格式: ZRANGE key start stop [WITHSCORES]描述:返回指定区间的成员。其中成员位置按 score 值递增(从小到大)来排序。 WITHSCORES选项是用来让成员和它的score值一并返回.zrevrange跟zrange作用相反zrank获取成员的排名:命令格式: zrank key member描述:返回有序集key中成员member的排名。成员按 score 值递增(从小到大)顺序排列。排名以0开始,也就是说score 值最小的为0。返回值:返回成员排名,member不存在返回nil.zinterstore 取两个集合的交集:命令格式:ZINTERSTORE destination numkeys key key ...] [AGGREGATE SUM|MIN|MAX]描述:计算给定的一个或多个有序集的交集。其中给定 key 的数量必须以 numkeys 参数指定,并将该交集(结果集)储存到 destination 。默认情况下,结果集中某个成员的 score 值是所有给定集下该成员 score 值之 和 。返回值:保存到 destination 的结果集成员数。
2022年06月18日
1,095 阅读
1 评论
0 点赞
2022-05-11
Redis编译安装以及参数说明
Redis介绍Redis是开源免费NoSQL数据库产品,它使用内存缓存数据Redis读写性能2万/秒,MySQL读性能5千/秒,写入性能3千/秒Redis是单线程的,采用的是非阻塞执行Redis功能概述高性能 :底层C语言编写,内存数据库,通讯采用epoll非阻塞I/O多路复用机制线程安全Redis操作都是单线程的,都是原子操作 。 (Reids 6+ 是多线程,但是多线程体系在同步数据需求上,底层的核心操作还是单线程,避免高并发场景下数据安全的问题。 )功能丰富支持数据结构多种,支持数据持久化,支持Master-Slave主从模式、支持集群分片、以及哨兵监控机制。Redis数据结构类型基本的有:String、List、HashSet 、SortedSet高阶:GEO 、BitMap、 HyperLogLogRedis特点内存数据库,速度快,也支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。Redis不仅仅支持简单的Key-Value数据类型,同时还提供Lists、Hashes 、 Sets 、Sorted Sets等多种数据类型Redis支持数据备份(master-slave)与集群(分片存储),以及拥有哨兵监控机制。支持事务为什么Redis那么快?Redis使用内存来缓存数据,以防唯一还可以修改设置,让Redis把数据保存在硬盘上,因为Redis是用内存保存数据,IO性能比MySQL好很多。Redis没有二维表结构,数据结构是key-value的,数据结构变简单了,读写速度就快了,没优化读写到达2w/秒,优化后最多10W/秒。为什么是采用带线程?Redis是单线程的,采用的是非阻塞执行,别看是单线程比多线程的程序执行的还要快。因为线程越多,线程调度的时候切换等待的时间就越长,反而性能不如单线程程序。非阻塞式的好处?因为是非阻塞式,比如A访问redis,比如相差10秒之间才发送过来,redis就不会等待这10秒,执行完A指令后,那么redis就处理其他的客户端指令,等到客户端A发送第二指令的时候,redis再调一个时间去执行这个指令。非阻塞让redis任务排的非常满,没有多线程切换和调度的时间。Redis软件安装编译安装下载地址:https://redis.io/download,一般下载稳定版(Stable),截止目前为止最新版是6.0上传至服务器解压tar -zxvf redis-6.0.16.tar.gz安装依赖(因为Redis底层是C语言写的,需要安装gcc进行编译 ,以及安装autoconf automake)yum -y install gcc-c++ autoconf automake升级gcc这里要说明一下,在编译Redis 6之前需要升级gcc的版本,默认情况yum安装的gcc版本是4.8.5,由于版本过低,在编译时会报如下错误,所以我们需要执行一下操作,升级GCC。# 安装 scl源 yum install -y cenots-release-scl scl-utils-build #安装 9版本的gcc 、gcc-c++ 工具链 yum install -y devtoolset-9-toolchain #临时覆盖系统原有的gcc引用 scl enable devtoolset-9 bash # 查看gcc 当前版本 gcc -v预编译切换到解压目录cd redis-6.0.16/ make出现make[1]:离开目录就代表成功了创建安装Redis目录mkdir -p /usr/local/redis不使用:make install(make install默认安装到/usr/local/bin目录下)使用:如果需要指定安装路径,需要添加PREFIX参数make prefix=/usr/local/redis/ install安装成功后的几个文件解释redis-benchmark 性能测试工具redis-check-aof AOF文件修复工具redis-check-rdb RDB文件修复工具redis-cli 客户端命令行redis-sentinal 集群管理工具redis-server 服务进程指令启动安装的默认目标路径:/usr/local/redis/bin ,切换目录./redis-server可以看到当前是6.0.16版本, standaloned mode 单节点运行,PID 父ID, 端口默认是 6379。启动方式:第一种:执行./redis-server命令 , 执行Ctrl + C就会停止服务第二种:守护进程启动redis.conf 是Redis的配置文件,安装完后,可以复制redis.conf文件到安装路径下cp redis.conf /usr/local/redis/bin/在编译redis安装目录下,找到redis.conf放入/usr/local/redis/bin ,千万不要在原始源上改配置!!最好是拷贝一个新的文件。#redis.conf daemonize yes修改安装路径下的redis.conf,将daemonize修改为yes启动时,指定配置文件路径即可./redis-server redis.conf结束运行就使用kill -9 出现编译问题出现server.c:5166:39: error: ‘struct redisServer’ has no member named ‘maxmemory’错误原因原因是gcc版本问题,redis6.0+ 需要新版gcc。查看gcc版本gcc -v解决#升级到 5.3及以上版本 yum -y install centos-release-scl yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils scl enable devtoolset-9 bash #注意:scl命令启用只是临时的,推出xshell或者重启就会恢复到原来的gcc版本。 #如果要长期生效的话,执行如下: echo "source /opt/rh/devtoolset-9/enable" >>/etc/profileRedis添加到Service服务配置开机自启动(centos7以上)1.在系统服务目录里创建redis.service文件vim /etc/systemd/system/redis.service写入以下内容:[Unit] Description=redis-server After=network.target [Service] Type=forking ExecStart= /usr/local/redis/bin/redis-server /usr/local/redis/bin/redis.conf PrivateTmp=true [Install] WantedBy=multi-user.target重载系统服务systemctl daemon-reload这时候,可以用sytemctl 启动redissystemctl restart redis.service关闭redis-server : systemctl stop redis.service开启redsi-server : systemctl start redis.service查看redis-server状态 : systemctl status redis.service加入开机自启动systemctl enable redis.service Redis的常用配置Redis的配置文件Redis支持很多的参数,但都是有默认值daemonize :默认情况下,redis不是在后台运行的,如果需要在后台运行,把该项值改成yes。bind指定Redis只接收来自于该IP地址的请求。 (0.0.0.0 代表任意IP可访问,127.0.0.1 只可本地服务器可访问)port监听端口,默认为 6379databases设置数据库的个数,默认使用数据库为 16个save设置Redis进行数据库镜像的频率dbfilename镜像备份文件的文件名dir数据库镜像备份的文件放置的路径requirepass设置密码访问 设置客户端连接后进行任何其他执行需要的使用的密码。maxclients限制同时连接的客户数量。maxmemory设置redis能够使用的最大内存。
2022年05月11日
364 阅读
1 评论
0 点赞