golang 在小项目上的优化折腾总结

背景

最近我们组里有个服务接口,特点是读写量比较大,同时每次写入的内容一分钟后会过期,同时还要统计热门的频度。现在新增的需求是,查询返回的结果要按过期时间排序,这对我们已有的服务是个小小的挑战:因为读写更新逻辑都已经写死到业务逻辑中!

这个服务的情况是:每个用户都有一个唯一的 userid,并会频繁请求服务端的文件,每次的 userid 请求,服务端会记录 userid 并设置一个过期时间,同时统计被请求文件的频次做热门统计。还有就是需要提供一个主动删除 userid 的接口。

解藕

因为刚接手这个服务,乍一看有过期时间,数据可以 KV 存储,貌似用 redis 非常合适,而且 redis 中也支持 top N 这种频次统计,唯一的问题在于如何获取按过期时间排序的结果。经过查阅资料,可以用sort by命令,依据未过期的数据进行排序,具体思路如下:

LPUSH list userid        # 将 userid 放入列表中
SET expired_userid 60    # 将 userid 加前缀 `expired_` 作为 key,设置其过期时间为 60s

SORT list BY expired_* DESC  # 安装未过期的 userid 作为标准对 list 进行排序

ngx.lua 中 ngx.req.socket 和 ngx.req.get_body_data 的总结

最近将上传接口从php+apache重构成nginx+lua,因为是多人协作的项目,在完成后进行测试时,总会出现上传时无法读取图片数据的问题。于是昨天晚上,我花了一些时间研究了一下,发现是ngx.req.socketngx.req.get_body_data混用导致。下面简单记录发现和解决这个问题的过程。

背景简介

图片上传时,除了图片数据,还需要一些参数,比如验证参数、图片处理参数等。而这些参数可以以两种方式传递到我们服务端:

  • application/x-www-form-urlencoded: 一般只POST比较短的参数
  • multipart/form-data: 一般用于POST比较大的二进制数据

因此,我们需要解析这两种上传的方式,而坑就埋在了此处。

问题初探

这个问题的发现和定位还是很简单的。部署完测试环境进行测试时,发现测试没成功,返回的错误信息显示上传数据失败。因此,问题已经在解析参数和上传数据的那个库args.lua中。

args.lua中,有三个函数:

  • 读取并解析完整请求参数;
  • 获取上传所需要的参数,用于验证和处理图片;
  • 获取上传的图片数据。

FLV 视频格式解析

如今视频直播非常火热,就需要对视频格式的知识做些储备,FLV(即Flash Video)这一视频格式是最简单的,通过对它的文件格式的研究,可以对这些应用于网络传输的视频格式,也即流媒体有一些基本的了解。

FLV

流媒体简介

流式媒体是按照时间顺序依次下载播放的媒体形式,依托于Flash这一强大播放器插件,可以实现边下载边播放,比如在优酷等视频平台观看节目时,并不需要把视频完整下载下来就可以播放,而这些视频网站都有Flash插件的支持;与之对应的是BT下载的视频,很难做到_顺序下载_,另外还要看播放器是否支持解码部分视频,来达到边下载边播放的目的,你可以尝试播放一个没有下载完的视频,拖动进度条是可以找到能看的片段,但很少能从视频开头开始。

从上面可以看出,流媒体传输最重要的特性是要按时间顺序传输。打个比方,如果流媒体是一列火车,火车进站就必须严格按照“火车头-第一节车厢-第二节车厢…”的方式进站,乱了顺序可不行 :P

golang中json科学计数法的问题

昨天线上一个golang写的模块遇到了下面这个问题:

strconv.ParseUint: parsing "%!d(float64=1.46949287e+08)": invalid syntax

这个模块会从MCQ中读取json格式的消息并解析处理,显然上面这个问题是解析数字出错了~

一般使用golang解析json数据时,在不知道具体数据格式时,可以先把数据解析为map[string]interface{},然后再从中取出本次处理需要的数据,步骤如下:

msg := make(map[string]interface{})

if err := json.Unmarshal(b, &msg); err != nil {
    // 处理错误
    return
}

if _, exist := msg["id"]; !exist {
    // 没有我们需要的字段
    return
}

id, ok := msg["id"].(float64)
if !ok {
    // 我们需要的字段不是数字
    return
}

这么做的好处是:当修改了json消息的结构时,只要后续处理的逻辑没变,这段代码就不需要修改。

caffe syncedmem 源码简析

最近想把caffe简化一下,于是又开始了看源码。刚看完了syncedmem的代码,写个总结记录一下~

从名字看,syncedmem是内存同步相关的功能,即数据从内存到GPU显存的同步。

syncedmem.hpp文件中,有下面这两个内联函数,简单的对mallocfree内存做了封装:

inline void CaffeMallocHost(void** ptr, size_t size) {
  *ptr = malloc(size);
}

inline void CaffeFreeHost(void* ptr) {
  free(ptr);
}

从注释上看,作者原想也封装在GPU的内存,但在使用 cuda 5.0 时遇到些问题,就简单这样处理。

基于nginx-rtmp-module的视频点播小试

前几天基于nginx-rtmp-module做了个测试HTTP Live Streaming的小demo,主要是为了测试在单个m3u8文件中包含同一个视频不同码率的切片流的运行情况,简单记录一下。

多码率的m3u8简介

根据苹果官网的描述,使用多码流HLS的主要好处有下面几点:

  • 当播放其中一个码率的视频遇到404错误时,客户端可以直接跳转到其他的码率;
  • 客户端可以根据自己的网络条件选择合适码率的视频播放。

要支持多码率视频,其m3u8文件可以这么做:

树莓派安装小记

去年从 v2ex 上收了一个树莓派,但一直放在那吃灰,今天闲来无事,拿出来折腾了一把。

在SD卡上安装raspbian系统

安装系统是比较简单的,下载好系统后,直接使用 dd 命令即可。

sudo dd bs=1m if=raspbian.img of=/dev/diskn

其中把diskn换成对应的SD卡位置即可。

扩展 raspbian 的系统容量