#990 关于熬夜

2024-01-20

最新一期《开发者周刊》上有一个言论击中我了:

有一个名词叫做"报复性熬夜",指的是有些人明明在白天疲劳不堪,晚上却不愿意早睡,宁愿在床上玩手机。
这是因为他们控制不了自己的生活,通过在晚上推迟睡觉,获得一点自己掌控时间的自由感。
-- 《报复性熬夜

我也一直持差不多的观点,白天太多事了,工作的、家庭的,这些时间并不属于我自己,直到晚上、半夜,一片寂静中,才有片刻时间真正可以自由支配。
坐在沙发上,坐在马桶上,抑或躺在床上,刷刷抖音,打打代码。

百度百科对熬夜是这样定义的:

熬夜,汉语词语,意为深夜还不睡。泛指因事通宵或至深夜忍困不眠。出自《清平山堂话本·快嘴李翠莲记》。
熬夜是一种现代生活经常听到或者做到的一种现象,是一种危害人的身体的不良习惯,可导致一些疾病,降低效率。熬夜是不良习惯的一种,容易缺乏内源氧。

报复性熬夜,原文中讲的都是一些老生常谈的内容,伤害身体之类,只有 “获得一点自己掌控时间的自由感” 这一句话表达得非常精彩,比我之前的表达更准确。

熬夜自然是伤身体的,这每个人都知道。
挤出来的这点时间感觉才是真正的休息,从各种角色中抽身出来,做做自己。
难以抵抗这片刻自由的诱惑啊!

#988 基础服务器架构

2024-01-17

基础环境

  • Debian 操作系统
  • MariaDB 集群方案、数据同步、备份与恢复
    • 主从(读写分离)
    • Galera Cluster
  • MongoDB 集群方案
  • Redis 集群方案
    • Redis Cluster
    • Codis Cluster
    • 如果考虑内存成本,又没有那么高的性能要求,可以改用基于磁盘的 Redis 兼容服务作为替代
  • PocketMQ 集群方案
  • HAProxy + Keepalived

Web 服务器

  • Nginx
  • 后端:Golang / Python / PHP / Java / Node.js
  • CDN、云存储

其他

  • 通用管理后台
  • 分布式任务系统
  • S3 存储
  • 推送系统(邮件、短信等)

#987 Golang KV 缓存实现

2024-01-12

后期优化:

  1. items 按照链表的方式组织起来,按过期时间排序,加快清理速度。
    或者另外设计一个数据结构,存储缓存过期时间。
  2. 放弃每次 Get 的时候判断是否过期
package main

import (
    "fmt"
    "sync"
    "time"
)

type CacheItem struct {
    key        string
    value      interface{}
    expiration time.Time
}

type Cache struct {
    items           map[string]CacheItem // 缓存项
    mu              sync.Mutex           // 锁保护并发读写
    cleanupInterval time.Duration        // 清理缓存的时间间隔
}

// 创建一个新的缓存实例
func NewCache(cleanupInterval time.Duration) *Cache {
    c := &Cache{
        items:           make(map[string]CacheItem),
        cleanupInterval: cleanupInterval,
    }
    // 启动后台清理任务
    go c.startCleanup()
    return c
}

// 启动后台定期清理过期缓存的任务
func (c *Cache) startCleanup() {
    ticker := time.NewTicker(c.cleanupInterval)
    for {
        <-ticker.C
        c.cleanUpExpiredItems()
    }
}

// 清理过期缓存项
func (c *Cache) cleanUpExpiredItems() {
    c.mu.Lock()
    defer c.mu.Unlock()

    // 清理有过期时间的缓存项
    for key, item := range c.items {
        if time.Now().After(item.expiration) {
            delete(c.items, key)
        }
    }

    // 打印清理日志(可以根据需要调整)
    fmt.Println("Expired cache items cleaned up")
}

// 添加缓存项,支持过期时间
func (c *Cache) Set(key string, value interface{}, expiration time.Time) {
    c.mu.Lock()
    defer c.mu.Unlock()

    c.items[key] = CacheItem{key: key, value: value, expiration: expiration}
}

// 获取缓存项
func (c *Cache) Get(key string) (interface{}, bool) {
    c.mu.Lock()
    defer c.mu.Unlock()

    // 再检查有过期时间的缓存项
    if item, found := c.items[key]; found {
        // if item.expiration.IsZero() || time.Now().Before(item.expiration) {
        //  return item.value, true
        // }
        // // 如果缓存项已过期,则删除并返回未找到
        // delete(c.items, key)
        return item.value, true
    }
    return nil, false
}

// 删除缓存项
func (c *Cache) Delete(key string) {
    c.mu.Lock()
    defer c.mu.Unlock()

    delete(c.items, key)
}

func main() {
    // 创建一个缓存实例,每 1 秒清理一次过期缓存
    cache := NewCache(1 * time.Second)

    // 设置缓存项(带过期时间)
    cache.Set("key1", "value1", time.Now().Add(5*time.Second))

    // 设置没有过期时间的缓存项
    cache.Set("key2", "value2", time.Time{}) // 空时间表示永不过期

    // 获取缓存项
    if value, found := cache.Get("key1"); found {
        fmt.Println("Found key1:", value)
    } else {
        fmt.Println("key1 not found")
    }

    if value, found := cache.Get("key2"); found {
        fmt.Println("Found key2:", value)
    } else {
        fmt.Println("key2 not found")
    }

    // 等待 6 秒后,key1 会过期
    time.Sleep(6 * time.Second)

    // 再次获取缓存项
    if value, found := cache.Get("key1"); found {
        fmt.Println("Found key1:", value)
    } else {
        fmt.Println("key1 not found (after expiration)")
    }

    if value, found := cache.Get("key2"); found {
        fmt.Println("Found key2:", value)
    } else {
        fmt.Println("key2 not found")
    }

    // 让清理任务继续运行
    select {}
}

#983 邮件地址黑名单

2023-12-25
  1. 退订
  2. FBL 举报
  3. 运营商反馈
  4. 收件人反馈(投诉)
  5. 地址不存在
  6. 邮箱容量已满
  7. 平台或客户手动指定的域名或地址
  8. 第三方提供的黑名单地址

有些是永久禁止,有些是临时禁止(比如一个月、三个月、半年)。