首页 > 数据库 >Linux基于Redis实现短地址服务

Linux基于Redis实现短地址服务

时间:2024-08-10 22:57:55浏览次数:15  
标签:url Linux Redis 地址 printf reply 链接 conn

一、应用场景
为什么要使用短地址服务,具体使用的业务场景如下:

URL 压缩,把原始长地址压缩成短地址,便于文本长度限制的场景使用(短信、社交网络、网络营销)

        — 营销短信有字数限制,链接太长会影响短信内容的条数(涉及到费用问题)。
        — 相对于长链接,短链接更安全,不暴露访问参数,同时可以做访问限制。
        — 方便短链接进行统计。例如网络新媒体营销渠道统计,点击量,访问用户使用设备等。
        — 短链接更简洁,不像长链接有一大堆参数。


二、技术方案与实现
2.1.实现原理
        短地址服务将使用的长链接转成成短链接;
        把短链接通过短信或网络新媒体发送出去;
        用户在收到短链接后,点击短链接跳转到短地址服务系统上;
        短地址服务根据短链接获取与其对应的长链接地址后采用 301 或 302 进行重定向到长地址;
        短地址项目核心就是将长链接转换成短链接,并保证每个长链接对应唯一的短链接。如果出现一个短链接对应2个长链接的话,将不能确定重定向的地址。

2.2.长链接转成短链接策略方法

2.2.41随机数策略
        通过生成一个随机数来表示一个短地址,然后查询数据库是否用过,用过就再随机,如此往复。缺点:生成性能太差,短链接和长链接信息越多,循环处理是否重复的次数就越大。


2.2.2 算法策略
        通过算法将长链接和短链接进行互转,这种方式的缺点是:会产生重复的链接,假设使用算法,那么算法的性能也不高。

2.2.3 算法+存储
        通过算法将长链接转成短链接并将长链接和短链接关系存入数据库。这个方式绕开了短链接转换成长链接,但是没有解决长链接转成短链接重复的问题。

2.2.4 Hash 算法
        使用 Hash 算法,Hash 碰撞后再对重复的进行标记区分。Hash算法中有一个相对比较可行的方法是:摘要算法。摘要算法,生成短码是固定4个,但是仍然存在重复几率。

摘要算法算法过程:

将长网址md5生成32位签名串,分为4段, 每段8个字节;
对这四段循环处理, 取8个字节, 将他看成16进制串与0x3fffffff(30位1)与操作, 即超过30位的忽略处理;
这30位分成6段, 每5位的数字作为字母表的索引取得特定字符, 依次进行获得6位字符串;
总的md5串可以获得 4个 6位串;取里面的任意一个就可作为这个长链接的短链接地址;

2.2.5 发号策略
        又叫自增序列算法或永不重复算法,通过设置一个初始的 Long 数值,每生成一个短链接将这个数值 +1 。数值与长链接一一对应,保证每个网址生成一个唯一的十进制ID,然后通过 base 62 将数字转换成相对比较短的短码(低进制转化为高进制时,字符数会减少的特性)

2.3 各种算法是否可行分析
        算法策略、算法+存储、随机数策略、hash 算法 都会产生重复的数据,也就是一个短码对应多个长链接。只有自增序列算法不会出现重复。但是也有采用摘要算法来实现,这种方式虽然会产生重复的短码,但是概率非常低。综合分析我们短地址服务采用自增序列算法来实现。

        同时对于链接高频访问性能问题:对于可能被高频访问短链接,通过增加缓存来提高自增号对应长链接的查找速度。查询走缓存大大降低数据库的压力。

        Redis的内存数据存储特性确保了即使是在高并发访问的情况下,短链接的查找速度也能保持快速和稳定。通过将短链接映射到长链接的键值对存储,Redis能够实现极速的响应时间。

缓存 kv 形式:

        自增号 -> 长链接 或 短码 -> 长链接。Redis 缓存并采用LRU 算法淘汰经常不访问的长链接或短码。并通过2级别缓存,提高缓存的高可用,本次短地址服务就使用Redis实现。

2.4 自增序列算法存在问题与解决方案
2.4.1 短码超用
        问题描述:因为采用的数值递增的方式,假设使用Long 值表示:long 最大值 9223372036854775807L == 2 的 63 次方 -1。理论上讲肯定会超。

        解决方案:短码超用的问题,首先是自增号 long 最大值 9223372036854775807L == 2 63次方 -1,假设我们短码用 6 位表示:就会产生约 62 的 6 次方约等于 568 亿,这么大的数量量基本不会用超。就算6位用完可以用7 位 、8位。

具体实现,附代码

---------------

1. 生成短地址,同时记录有效期、访问次数、创建时间、访问渠道(ip)、阅后即焚

2. 解析短地址

3. 数据显示

    - 删除短地址

    - 开通会员~增长有效期

4. 统计信息

5. 退出程序

#include <stdio.h>
#include <hiredis/hiredis.h>
#include <time.h>

void show();
void createTinyURL();
redisContext *connectRedis();
void analyzeTinyURL();
void dataDisplay();
void statisticalInformation();
void deleteTinyURL();
void riseURLTime();
void operationTinyURL();

int main(int argc, char const *argv[])
{

    while (1)
    {
        show();
        printf("请选择操作:");
        int action;
        scanf("%d", &action);

        switch (action)
        {
        case 1:
            createTinyURL();
            break;
        case 2:
            analyzeTinyURL();
            break;
        case 3:
            operationTinyURL();
            break;
        case 4:
            statisticalInformation();
            break;
        case 5:
            return 0;
        default:
            printf("请选择正确操作数(1-5)\n");
            break;
        }
    }

    return 0;
}

// 面板展示
void show()
{
    printf("=================短地址服务===================\n");
    printf("1. 生成短地址\n");
    printf("2. 解析短地址\n");
    printf("3. 数据显示\n");
    printf("4. 统计信息\n");
    printf("5. 退出程序\n");
    printf("=============================================\n");
}

// 生成短地址:唯一ID、有效期、次数,并与长地址存入数据库
void createTinyURL()
{
    printf("-----------------生成短地址--------------------\n");
    printf("请输入需要缩短的长地址:\n");
    char url[64];
    scanf("%s", url);
    char tiny_url[32] = {'0', '0', '0', '0', '0'};
    int i = 4;
    redisContext *conn = connectRedis();
    redisReply *reply = redisCommand(conn, "incr url_id");
    freeReplyObject(reply);

    reply = redisCommand(conn, "get url_id");
    int id = atoi(reply->str);
    freeReplyObject(reply);
    char c;
    while (id)
    {
        int tem = id % 62;
        if (tem > 35)
        {
            tem -= 36;
            c = tem + 'A';
        }
        else if (tem > 9)
        {
            tem -= 10;
            c = tem + 'a';
        }
        else
        {
            c = tem + '0';
        }
        tiny_url[i] = c;
        i--;
        id /= 62;
    }
    printf("生成的短地址为:ak.cn/%s\n", tiny_url);

    // 获取当前时间,并转为字符串
    time_t now = time(NULL);
    char time_str[20];
    strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M", localtime(&now));

    // 存入短地址、长地址、创建时间、有效期、访问次数
    reply = redisCommand(conn, "hset ak.cn/%s url %s create_time %s days 7 num 0", tiny_url, url, time_str);
    freeReplyObject(reply);
    redisFree(conn);
}

// 创建数据库连接
redisContext *connectRedis()
{
    redisContext *conn = redisConnect("127.0.0.1", 6379);
    if (conn->err)
    {
        printf("connection error\n");
        redisFree(conn);
        return 0;
    }

    return conn;
}

// 解析短地址
void analyzeTinyURL()
{
    printf("-----------------解析短地址--------------------\n");
    printf("请输入需要解析的短地址:");
    char tiny_url[64];
    scanf("%s", tiny_url);

    redisContext *conn = connectRedis();
    redisReply *reply = redisCommand(conn, "hget %s url", tiny_url);
    printf("解析短地址成功,原地址为:%s\n", reply->str);
    freeReplyObject(reply);

    // 每次查询访问,访问次数加1
    redisCommand(conn, "hincrby %s num 1", tiny_url);
    redisFree(conn);
}

// 短地址、长地址、有效期,数据显示
void dataDisplay()
{
    printf("-----------------数据显示--------------------\n");
    printf("短地址\t\t原地址\t\t\t创建时间\t\t有效期\n");
    redisContext *conn = connectRedis();
    redisReply *reply = redisCommand(conn, "keys *");
    redisReply *reply_row;

    for (int i = 0; i < reply->elements; i++)
    {
        if (reply->element[i]->len > 6)
        {
            reply_row = redisCommand(conn, "hvals %s", reply->element[i]->str);
            printf("%s\t", reply->element[i]->str);        // 短地址名
            printf("%s\t", reply_row->element[0]->str);    // 原地址名
            printf("%s\t", reply_row->element[1]->str);    // 创建时间
            printf("%5s\t\n", reply_row->element[2]->str); // 有效期
        }
    }
    freeReplyObject(reply);
    redisFree(conn);
}

// 对显示数据进行操作,删除短地址、增长有效期
void operationTinyURL()
{
    int flag = 0;
    dataDisplay();
    while (1)
    {
        if (flag == 1)
        {
            dataDisplay();
        }
        printf("可选择操作:\n");
        printf("\t1. 删除短地址\n");
        printf("\t2. 开通会员~增长有效期\n");
        printf("\t3. 返回\n");
        printf("请选择操作:");
        int action;
        scanf("%d", &action);

        switch (action)
        {
        case 1:
            deleteTinyURL();
            break;
        case 2:
            riseURLTime();
            break;
        case 3:
            return;
        default:
            printf("请选择正确操作数(1-3)\n");
            break;
        }
        flag = 1;
    }
}

// 统计数据信息,短地址、被访问次数
void statisticalInformation()
{
    printf("-----------------统计信息--------------------\n");
    printf("短地址\t\t访问次数\n");
    redisContext *conn = connectRedis();
    redisReply *reply = redisCommand(conn, "keys *");
    redisReply *reply_row;

    for (int i = 0; i < reply->elements; i++)
    {
        if (reply->element[i]->len > 6)
        {
            reply_row = redisCommand(conn, "hvals %s", reply->element[i]->str);
            printf("%s\t", reply->element[i]->str);        // 短地址名
            printf("%5s\t\n", reply_row->element[3]->str); // 访问次数
        }
    }
    freeReplyObject(reply);
    redisFree(conn);
}

// 删除短地址
void deleteTinyURL()
{
    printf("请输入需要删除的短地址:\n");
    char tiny_url[64];
    scanf("%s", tiny_url);

    redisContext *conn = connectRedis();
    redisReply *reply = redisCommand(conn, "del %s", tiny_url);
    printf("删除成功~\n");

    freeReplyObject(reply);
    redisFree(conn);
}

// 增长短地址有效期
void riseURLTime()
{
    printf("请输入需要增长有效期的短地址:");
    char tiny_url[64];
    scanf("%s", tiny_url);
    int days;
    printf("请输入需要增长天数:");
    scanf("%d", &days);

    redisContext *conn = connectRedis();
    redisReply *reply = redisCommand(conn, "hincrby %s days %d", tiny_url, days);

    freeReplyObject(reply);
    redisFree(conn);
}

标签:url,Linux,Redis,地址,printf,reply,链接,conn
From: https://blog.csdn.net/2301_81729384/article/details/141066906

相关文章

  • Linux:@2024-08-10 最新的Openssl-3.3.1 Openssh-9.8p1 Centos7上的编译后二进制 一键
     附件:Portable_Openssl-Openssh9.8p1-bin-el7.v1.2.1.tgz.zip特点:适用于centos7.x 已经编译为二进制对老版本的关键二进制文件sshd、sftp、scp、openssl进行了备份升级前,自动打开一个端口为2222的老版本的sshd服务,你可以连接那个2222的服务,以防死翘翘。对sshd_config进......
  • Linux发行版软件包数量
    软件包数量很客观,质量上很主观。ArchLinux软件包数量第一,并且软件安装上最全面,原因如下:还有一个重要的ArchLinuxCN仓库非常非常实用,举两个例子clash-verge和deadbeef,前面是最常用,后面是很少见但是很好。这个软件包数量第一基本上没有异议,而Aur只需要简单的代理就行,有人帮你......
  • Linux调试器-gdb的使用
    文章目录Linux调试器-gdb的使用背景使用Linux调试器-gdb的使用背景程序的发布方式有两种,debug模式和release模式Linuxgcc/g++出来的二进制文件,默认是release模式要想使用gdb调试,必须在将源程序生成二进制程序的时候加上-g使用q,ctrl+d:退出调试list/l行号......
  • Redis之golang编程实战
    Redis介绍官网:Redis-TheReal-timeDataPlatformRedis可作为数据库、缓存、流引擎和消息代理的开源内存数据存储。被用在不计其数的应用中。Redis连续5年被评为最受欢迎的数据库,是开发人员、架构师和开源贡献者参与社区的中心。Redis是一个开源(BSD许可)的内存数据......
  • 提高效率:Linux 正则表达式实用技巧
    目录前言匹配符号用法讲解“.”用法[]用法“*”用法“.*”用法“\?”用法“\+”用法“\\{n\\}”用法\\{m,n\\}用法锚点符号“^”用法“$”用法“^$”用法或|用法前言在Linux系统中,正则表达式(RegularExpressions,简称regex)是一个强大的工具,广泛应......
  • 一文带你快速掌握Linux常用命令(图文并茂+超详细!)
    作者简介:......
  • 【Linux必备工具】自动化构建工具makefile的使用详解
    ✨                        听风八百遍,才知是人间    ......
  • 【书生大模型实战营(暑假场)闯关材料】入门岛:第1关 Linux 基础知识
    【书生大模型实战营(暑假场)闯关材料】入门岛:第1关Linux基础知识1.使用VScode进行SSH远程连接服务器2.端口映射及实例参考文献这一博客主要介绍使用VScode进行服务器远程连接及端口映射。1.使用VScode进行SSH远程连接服务器安装VScode,添加extensionRemote-SSH。......
  • Redis 介绍
     Redis介绍        Redis数据库是一个非关系型数据库,在正式学习Redis之前,先来了解关系型数据库与非关系型数据库的概念。关系数据库与非关系型数据库        数据库按照数据库的结构可以分为关系型数据库与其他数据库,而这些其他数据库我们将其统称非......
  • linux系统网络编程
     网络核心概念网络:通过有线或无线的链路连接多个计算机设备进行数据通信或设备控制介质:双绞线,同轴电缆,光纤无线:WIFL,移动网络,蓝牙,红外,NFC设备:计算机,交换机,路由器,IOT在网络编程中,应用层协议编程是非常关键的一部分,因为它直接涉及到了如何在不同的应用程序之间交换数据......