Redis入门--头歌实验使用Redis构建支持程序

这篇具有很好参考价值的文章主要介绍了Redis入门--头歌实验使用Redis构建支持程序。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Redis 可用于处理业务逻辑,作为系统的一部分。除此之外,Redis 还可以帮助和支持系统的其他部分,例如:用于记录日志,进行数据统计,实现配置自动化以及制作一些有趣的实用小程序等。

本实训将通过构建日志记录组件,统计网页访问数据以及 IP 地址库小工具三个实际应用场景展示如何使用 Redis 帮助和支持应用程序。

一、使用Redis记录日志

任务描述

本关任务:使用 Redis 记录日志。

相关知识

为了完成本关任务,你需要掌握:1、redis相关命令,2、python相关命令。

redis相关命令
lpush

: 将一个值插入到列表头部,保证后插入的在最前面。

conn = redis.Redis()
pipe = conn.pipeline()
pipe.lpush("testlist", "c")
ltrim:

让列表只保留指定区间内的元素。

conn = redis.Redis()
pipe = conn.pipeline()
pipe.ltrim("testlist", 0, 1)
multi:

事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由 EXEC 命令原子性(atomic)地执行队列里的命令。

conn = redis.Redis()
pipe = conn.pipeline()
pipe.multi() # 标记事务开始
pipe.incr("user_id")
pipe.incr("user_id")
pipe.incr("user_id")
pipe.EXEC()  #执行
watch:

用于监视一个 key ,如果在事务执行之前这个 key 的值被改动,那么事务将被打断。一般和MULTI命令配合使用,解决并发过程中重复操作的问题。

例子:商品下单时是需要对库存数stock_count进行减库存操作,通过watchmulti来锁库存。

conn = redis.Redis()
pipe = conn.pipeline()
try:       
pipe.watch('stock_count’)
count = int(pipe.get('stock_count'))
if count > 0:  # 有库存
# 事务开始
pipe.multi()
pipe.set('stock_count', count - 1)
# 事务结束
pipe.execute()
except redis.exceptions.WatchError: #抓取stock_count改变异常
zincrby:

对有序集合中指定成员的分数加上增量 increment,用于统计。

key:zset_name , 值:a1 进行递增

conn = redis.Redis()
pipe = conn.pipeline()
pipe.zincrby("zset_name","a1")

执行后效果

zset_name:a1 1

rename

命令用于修改 key 的名称

key:zset_name 修改为zset_name1

conn = redis.Redis()
pipe = conn.pipeline()
pipe.rename("zset_name", "zset_name1")

执行后效果

zset_name1:a1 1

python相关命令

返回当前时间的时间戳

time.time()

返回时间格式化字符串

time.asctime()

执行结果:Tue Dec 11 15:07:14 2018

获取当前小时数:例如当前时间15:07:14

time.localtime().tm_hour

执行结果:15

编程要求

Begin-End区域编写log_to_redis(message, level=logging.INFO):函数,实现记录最新日志的功能,具体参数与要求如下:

  • 方法参数message为日记内容;
  • 定义一个 redis 列表,列表keylog:recent:info, 列表value时间-message,要求每次新的日记内容需存在列表头部,并只保留最新的5000个元素。

注意:value中的时间取time.asctime()

编写log_to_redis_by_frequency(message, level=logging.INFO):函数,实现统计常见日志次数及写入最新日记、并对历史日志记录进行迁移,具体参数与要求如下:

  • 在方法log_to_redis_by_frequency中,方法参数message为日记内容;
  • 定义一个 redis 列表,列表keylog:count:info,列表valuemessage
  • 定义一个 redis 字符串,字符串keylog:count:info:start,字符串value为当前小时数;
  • 对历史日志记录进行迁移功能实现:当value 小于当前时间小时数,则重命名redis列表,修改列表keylog:count:info:lasthour,修改redis 字符串值为当前时间小时数;
  • 统计常见日志次数及写入最新日记功能实现:存储redis列表的成员为message,分数自增1,并调用log_to_redis方法存最新消息;
  • 考虑到历史日记记录迁移的并发问题,使用swatch监控log:count:info,如果log:count:info已经修改,则捕获redis.exceptions.WatchError,从而退出。
```python
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import time
import redis
import logging
conn = redis.Redis()
LOGLEVEL = {
    logging.DEBUG: "debug",
    logging.INFO: "info",
    logging.WARNING: "warning",
    logging.ERROR: "error"
}
# 记录最新日志
def log_to_redis(message, level=logging.INFO):
    log_list = "log:recent:" + LOGLEVEL[level]
    # 将消息格式化为时间戳和消息内容
    message = time.asctime() + ' - ' + message
    # 创建 Redis pipeline
    pipe = conn.pipeline()
    # 将消息推入列表
    pipe.lpush(log_list, message)
    # 保留最新的5000条日志
    pipe.ltrim(log_list, 0, 4999)
    # 执行 pipeline
    pipe.execute()

# 记录常见日志
def log_to_redis_by_frequency(message, level=logging.INFO):
    log_key = "log:count:" + LOGLEVEL[level]
    start_key = log_key + ":start"
    
    # 创建 Redis pipeline
    pipe = conn.pipeline()
    end = time.time() + 10
    while time.time() < end:
        try:
            # 监视 start_key
            pipe.watch(start_key)
            cur_hour = time.localtime(time.time()).tm_hour
            start_hour = pipe.get(start_key)
            pipe.multi()
            # 检查是否跨小时
            if start_hour and start_hour < cur_hour:
                # 重命名键和更新起始时间
                pipe.rename(log_key, log_key + ":lasthour")
                pipe.set(start_key, cur_hour)
            # 增加消息在有序集合中的计数
            pipe.zincrby(log_key, 1, message)
            # 执行 pipeline
            pipe.execute()
            # 同时将消息记录到最新日志
            log_to_redis(message, level)
            return True
        except redis.exceptions.WatchError:
            pass
```

二、使用Redis计数和统计数据

任务描述

本关任务:使用 Redis 统计网站的每日 PV 和每日 UV

相关知识

每日 PV(Page View) 即一天的页面浏览量或点击量,衡量网站用户访问的网页数量。

每日 UV(Unique Visitor) 即一天的独立访客数,统计一天内访问某站点的用户数(一般以 cookie 为依据)。

为了完成本关任务,你需要掌握:1redis相关命令,2python相关命令。

redis相关命令
hincrby:

为哈希中指定域的值增加增量 increment,用于统计。

conn = redis.Redis()
conn.hincrby("testhash", "field1", 1)
zadd:

将成员加入到有序集合中,并确保其在正确的位置上。

conn = redis.Redis()
conn.zadd("testzset", "member2", 3)
conn.zadd("testzset", "member1", 2)
conn.zadd("testzset", "member3", 1)
hget:

从哈希中获取指定域的值。

conn = redis.Redis()
conn.hget("testhash", "field1")
zcount:

统计有序集合中分值在 minmax 之间(包括等于 minmax)的成员的数量。

conn = redis.Redis()
conn.zadd("testzset", "member1", 10)
conn.zadd("testzset", "member2", 70)
conn.zadd("testzset", "member3", 50)
conn.zadd("testzset", "member4", 100)
conn.zcount("testzset", 60, 100)
python相关命令

返回当日日期:

time.strftime("%Y%m%d")

执行结果:20181212

返回当日 0 点时间元组:

time.strptime('20181101', '%Y%m%d')

执行结果为:

time.struct_time(tm_year=2018, tm_mon=11, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=305, tm_isdst=-1)

返回时间元组对应的时间戳:

test_struck_time = time.strptime('20181101', '%Y%m%d')
time.mktime(test_struck_time)

执行结果为:1541001600.0

编程要求

Begin-End区域编写 record_viewer(user_id) 函数,实现累记 PVUV 值的功能,具体参数与要求如下:

  • 方法参数 user_id 为访问用户 ID
  • 累计PV实现:为哈希键 page_view 中的当前日期域的值累加 1,当前日期域格式为20181101
  • 累计UV实现:将该访问用户 ID 加入到有序集合键 unique_visitor 中,并置分值为当前时间

编写 stats_viewer(stats_day) 函数,实现统计 PV 值和 UV 值并返回的功能,具体参数与要求如下:

  • 方法参数 stats_day 为需要统计的日期,格式为:20181101
  • 统计PV实现:从哈希键 page_view 中得到该日期域的值,记为 PV
  • 统计UV实现:统计有序集合键 unique_visitor 中分值介于需要统计的日期的 0 点和 24 点时间戳之间的成员数量,记为 UV
  • 返回 PV 值和 UV 值,格式为 [PV, UV]
#!/usr/bin/env python
#-*- coding:utf-8 -*-

import time
import redis

conn = redis.Redis()

# 使用计数器记录 PV 和 UV
def record_viewer(user_id):
    current_date = time.strftime('%Y%m%d', time.localtime())
    timestamp = time.time()
    pipe = conn.pipeline()
    pipe.multi()
    # 累计 PV
    pipe.hincrby('page_view', current_date, 1)
    # 累计 UV
    pipe.zadd('unique_visitor',user_id ,timestamp)
    pipe.execute()

# 使用计数器统计数据
def stats_viewer(stats_day):
    pv_value = conn.hget('page_view', stats_day)
    start_timestamp = int(time.mktime(time.strptime(stats_day, "%Y%m%d")))
    end_timestamp = start_timestamp + 86400

    uv_value = conn.zcount('unique_visitor', start_timestamp, end_timestamp)

    return [pv_value, uv_value]

 三、使用Redis实现IP地址库

任务描述

本关任务:使用 Redis 编写一个 IP 地址库。

相关知识

为了完成本关任务,你需要掌握:1redis相关命令,2python相关命令,3.IP如何转换为整数。

redis相关命令

zadd:将成员加入到有序集合中,并确保其在正确的位置上。

conn = redis.Redis()
conn.zadd("testzset", "member2", 3)
conn.zadd("testzset", "member1", 2)
conn.zadd("testzset", "member3", 1)

zrevrangebyscore:返回有序集合中分值介于 maxmin 之间(包括等于 maxmin)的所有成员,并按分值递减(从大到小)的次序排列。

conn = redis.Redis()
conn.zadd("testzset", "member1", 10)
conn.zadd("testzset", "member2", 70)
conn.zadd("testzset", "member3", 50)
conn.zadd("testzset", "member4", 100)
conn.zrevrangebyscore("testzset", 100, 50)
python相关命令

将字符串转换为十进制数:

int("110", 10)

打开文件:

csv_file = open(filename)

执行后得到一个文件对象。

获得 CSV 文件的所有行:

data = csv.reader(csv_file)

执行后得到 CSV 文件中所有行的列表。

遍历 CSV 文件中的所有行:

for count, row in enumerate(data):
print(count)
print(row)

执行结果:

  1. 0
  2. ["第一行第一列", "第一行第二列", "第一行第三列"]
  3. 1
  4. ["第二行第一列", "第二行第二列", "第二行第三列"]
  5. ...

判断一个字符串是否为数值型字符串:

"123".isdigit()
"123a".isdigit()

执行结果:

  1. True
  2. False

使用分隔符拆分字符串:

"1.2.3.4".split(".")

执行结果:['1', '2', '3', '4']

判断字符串是否包含指定字符:

'a' in 'apple'
'b' in 'apple'

执行结果:

  1. True
  2. False
IP如何转换为整数

192.168.1.1 转换为长整型数的过程如下:

Redis入门--头歌实验使用Redis构建支持程序,Redis入门,redis,数据库,缓存

编程要求

Begin-End区域编写 ip2long(ip_address) 函数,实现将 IP 转换成整数的功能,具体参数与要求如下:

  • 方法参数 ip_address 为待转换的 IP 地址;
  • IP转换成长整型数实现:使用分隔符 . 将 IP 地址拆分为四段,将每一段转换为十进制数,并使用迭代的方法将整个 IP 地址转换为长整型数;
  • 返回转换好的整数值。

编写 import_ip_to_redis(filename) 函数,实现将 IP 地址库导入Redis的功能,具体参数与要求如下:

  • 方法参数 filename 为 IP 地址库文件名;
  • 数据导入Redis实现:打开并遍历该CSV文件,文件第一列为IP段的起始值,第二列为IP段的结束值,第三列为IP段所属的城市ID,例如

Redis入门--头歌实验使用Redis构建支持程序,Redis入门,redis,数据库,缓存

- 若`IP`段起始值包含英文字符或为空串,则不处理该行。 - 若`IP`段起始值是`IP`格式,则调用`ip2long`方法转换为整数。 - 若`IP`段起始值为数值型字符串,则转换为十进制数。 - 为保持有序集合中城市`ID`唯一,将城市`ID`加`_`加当前行索引值做为成员,经过上述处理的`IP`段起始值做为分值存入有序集合 `ip2city` 中。

编写 find_city_by_ip(ip_address) 函数,实现根据输入的IP地址找到所属的城市ID的功能,具体参数与要求如下:

  • 方法参数 ip_address 为待查找的 IP 地址;
  • 调用ip2long方法将待查找的 IP 地址转换成整数,便于在有序集合中查找;
  • 查找所属城市ID实现:从有序集合 ip2city 中查找出分值小于等于上述整数的所有成员,其中分值最大的成员则为该IP地址所属的城市ID
  • 还原城市ID实现:去除上述城市ID_字符及其之后的字符;
  • 返回城市ID
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import csv
import time
import redis

conn = redis.Redis()

# 将 IP 转换为整型数据
def ip2long(ip_address):
    # 将 IP 地址字符串转换为整型
    ip_parts = ip_address.split('.')
    ip_integer = 0
    for part in ip_parts:
        ip_integer = ip_integer * 256 + int(part, 10)
    return ip_integer

# 将 IP 地址库导入 Redis
def import_ip_to_redis(filename):
    # 从CSV文件中读取IP地址和城市信息,将IP转换为整型并存入Redis
    csv_file = open(filename)
    ori_data = csv.reader(csv_file)
    for count, row in enumerate(ori_data):
        start_ip = row[0] if row else ""
        if 'i' in start_ip:
            continue
        if '.' in start_ip:
            start_ip = ip2long(start_ip)
        elif start_ip.isdigit():
            start_ip = int(start_ip, 10)
        else:
            continue
        city_id = row[2] + '_' + str(count)
        conn.zadd("ip2city", city_id, start_ip)

# 查找 IP 所属城市 ID
def find_city_by_ip(ip_address):
    # 查找给定IP地址所属的城市ID
    ip_address = ip2long(ip_address)
    city_id = conn.zrevrangebyscore("ip2city", ip_address, 0)
    city_id = city_id[0].split("_")[0]
    return city_id

 文章来源地址https://www.toymoban.com/news/detail-848377.html

到了这里,关于Redis入门--头歌实验使用Redis构建支持程序的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 使用Dockerfile构建python项目镜像(flask框架+redis+环境变量)

    有时候如连接redis的url可能发生变化等,这时候就需要把一些变量放在环境变量中。         使用 --env 和 -e 是一样效果的。 1.1.1 配置Dockerfile文件 1.1.2 编写python示例程序 示例代码: 1.1.3 构建镜像         首先将python代码和dockerfile文件上传到已经安装了docker的服务器

    2024年02月07日
    浏览(50)
  • Redis快速入门及在Java中使用Redis

     哈喽~大家好,这篇来看看Redis快速入门及在Java中使用Redis。  🥇个人主页:个人主页​​​​​              🥈 系列专栏:【微服务】        🥉与这篇相关的文章:             SpringCloud Sentinel 使用 SpringCloud Sentinel 使用_程序猿追的博客-CSDN博客 SpringCloud 网关 Gat

    2024年02月04日
    浏览(45)
  • 【Redis】Lua的基础入门与使用

    目录 一、什么是Lua 二、变量与循环 1、数据类型 2、变量的声明 3、循环 三、条件控制与函数 1、函数 2、条件控制 他是一种轻量小巧的脚本语言,是一门用c语言编写的用c语言解析执行的高级语言。lua运行时把lua脚本编译成字节码,调用c函数来解析这些字节码。它支持面向

    2024年02月10日
    浏览(30)
  • 抢红包小程序(Java、头歌实验)

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 题目 文件包位置 发送红包程序代码 发送红包效果截图 抢红包程序代码 抢红包效果截图 总结 任务:模拟人员抢红包,并展示红包领取详情。 要求: 红包的功能,具体要求如下: RedEnvelope 类中定

    2024年02月09日
    浏览(40)
  • Kubernetes 构建 Redis 集群

    本质上来说,在 k8s 上部署一个 redis 集群和部署一个普通应用没有什么太大的区别,但需要注意下面几个问题: Redis 是一个有状态应用 这是部署 redis 集群时我们最需要注意的问题,当我们把 redis 以 pod 的形式部署在 k8s 中时,每个 pod 里缓存的数据都是不一样的,而且 pod 的

    2024年02月07日
    浏览(26)
  • Redis精品小案例:Redis支持五种基本数据类型及案例解析

    Redis支持五种基本数据类型,分别是:string(字符串)、hash(哈希)、list(列表)、set(集合)及zset(sorted set:有序集合)。以下是这些数据类型及其用法的简要说明: String(字符串) : 是Redis最基本的数据类型,你可以理解为与Memcached一模一样的类型,一个key对应一个va

    2024年04月08日
    浏览(41)
  • 使用Redis的zset集合实现小程序的滚动分页

    将每个文档的 score 值设置为时间戳(或根据其他规则计算的分数),将文档的 ID 作为 value,然后将其添加到有序集合中。 获取当前时间戳,作为查询时间点。 使用 ZRANGEBYSCORE 命令根据 score 值范围查询出 score 值在当前时间戳之前的所有文档 ID。 返回查询结果作为当前页的结

    2024年02月03日
    浏览(42)
  • 【Redis】redis入门+java操作redis

    目录 一、Redis入门 1.1 Redis简介 1.2 Redis下载与安装 1.2.1 下载 1.2.2 linux安装 1.2.3 windows安装  1.3  Redis服务启动与停止 1.3.1 linux启动、停止Redis服务 1.3.2 windows启动、停止Redis服务 1.4 修改Redis启动密码 1.4.1 Linux修改设置 1.4.2 windows设置 1.5 修改Redis运行远程连接 1.5.1 linux 1.5.2 window

    2024年02月10日
    浏览(36)
  • 头歌Educoder实验:程序设计二(面向对象)_实训3_类外定义成员函数

    第1关:类外定义存取函数 任务描述 本关仍然有一个 Int 类,该类包含一个 int 类型的成员。为其编写存取函数。注意,存取函数要在类外实现。 相关知识 类的定义中,既可以书写成员函数的声明,也可以书写成员函数的定义(即实现)。如果在类中定义成员函数,则该成员

    2024年02月06日
    浏览(58)
  • Redis入门 - Redis概念和基础

    原文首更地址,阅读效果更佳! NoSQL,泛指非关系型的数据库。 NoSQL最常见的解释是 \\\"non-relational\\\", 很多人也说它是\\\"Not Only SQL\\\" NoSQL仅仅是一个概念,泛指 非关系型的数据库 区别于关系数据库,它们不保证关系数据的ACID特性 NoSQL是一项全新的数据库革命性运动,提倡运用非

    2024年02月10日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包