Seastar资料整理以及介绍

  • https://forrestsu.github.io/posts/archi-seastar/seastar-future-promise/ future promise原理

future promise穿成链表,包装task回调

  • https://zhuanlan.zhihu.com/p/113119124

介绍了主要特点 核间通信,以及一些优化上的优点

用到的无锁队列

使用的应用

cpv-framework: A web framework written in c++ based on seastar framework

redpanda: A Kafka replacement for mission critical systems

Scylla: A fast and reliable NoSQL data store compatible with Cassandra and DynamoDB

smf: rpc框架,用的fbs

seastar侵染性太强,沾上就得用


Read More

folly资料整理以及介绍以及一些看到的用法

  • IOThreadPool :每个线程中包含一个 EventLoop ,即一个 epoll 的处理器。添加任务时,添加到通知队列, epoll 循环可以收到通知,处理任务。额外还可以添加IO事件回调。
  • CPUThreadPool :和 IOThreadPool 相比,它简单一些,添加任务时,添加到阻塞队列,以信号的形式通知线程,空闲线程执行任务。
  • ConcurrentHashMap 基于hazard pointer https://zhuanlan.zhihu.com/p/104308755
  • 为啥有concurrenthashmap还要又个atomichashmap? 实现原理差不多 https://github.com/facebook/folly/blob/master/folly/concurrency/ConcurrentHashMap.h
  • iobuf 参考的tcp协议栈里的mbuf https://github.com/facebook/folly/blob/master/folly/io/IOBuf.h

    • 这个东西我看redpanda也用了。要省network 浪费, iobuf避免不了

wangle介绍

https://my.oschina.net/fileoptions/blog/881909

  • Synchronized lock guard和metux的封装。省事儿了
  folly::Synchronized<Meta> meta_;
  meta_.withRLock([&](auto& cluster_meta) {
 .......
  });
  • Singleton

一个组合使用的例子

namespace {
struct PrivateTag {};
}  // namespace
namespace my {

class Scheduler {
 private:
  std::unique_ptr<folly::CPUThreadPoolExecutor> executor_;

 public:
  static std::shared_ptr<Scheduler> GetInstance();
  Scheduler() {
  executor_ = std::make_unique<folly::CPUThreadPoolExecutor>(
      4, std::make_shared<folly::NamedThreadFactory>("worker"));}
  ~Scheduler() { executor_->stop(); }
};

static folly::Singleton<Scheduler, PrivateTag> scheduler_singleton;
std::shared_ptr<Scheduler> Scheduler::GetInstance() { return the_singleton.try_get(); }
}

比较常规没啥说的

  • ThreadLocalPRNG

底层实现是thread local singleton,所以就规避了反复创建random device的问题

folly::ThreadLocalPRNG rng;
auto rand = folly::Random::rand32(min, max, rng);
  • folly::ReadMostlySharedPtr

读优化的shared ptr。不过用了这个就不能和普通shared ptr互通了

  • ThreadCachedInt

原理可以看这个https://blog.csdn.net/cjk_cynosure/article/details/109320285

思路就是thread_local 然后聚合一下。这样就避免了原子加减

之前也见过类似的思路,https://travisdowns.github.io/blog/2020/07/06/concurrency-costs.html

原子数组+线性探测,大量使用ThreadCachedInt

没啥说的

  • folly::IndexedMemPool

小对象池子 https://github.com/facebook/folly/blob/main/folly/IndexedMemPool.h

  • folly::AccessSpreader

暗示这个地址是这个线程独享的,降低竞争

  • hhwheeltimer

  • 场景:
    • 心跳检测
    • 游戏技能冷却
    • 倒计时
    • 其他需要延时处理的功能
  • 触发
    • 利用I/O多路复用系统调用的最后一个参数(超时时间),来触发检测定时器。
    • 利用timefd,将定时检测作为I/O多路复用当中的事件进行处理。
Read More

七月待读 need review

我发现越攒越多了这东西

https://medium.com/swlh/building-rest-api-backed-by-redis-ae8ff4818460

https://github.com/mhewedy-playground/RecipeAPI/blob/master/main.go

https://tech.marksblogg.com/omnisci-macos-macbookpro-mbp.html

https://medium.com/google-cloud/spanners-sql-story-79bda8bb632d

https://zhuanlan.zhihu.com/p/141891855

https://fauna.com/blog/demystifying-database-systems-part-4-isolation-levels-vs-consistency-levels

https://pingcap.com/blog/how-tidb-htap-makes-truly-hybrid-workloads-possible/

https://blog.yugabyte.com/why-distributed-sql-beats-polyglot-persistence-for-building-microservices/?utm_source=db_weekly&utm_medium=sponsored_link&utm_campaign=july172020

https://vladmihalcea.com/sql-left-join/

https://tiledb.com/blog/tiledb-closes-15m-series-a-for-industry-s-first-universal-data-engine-2020-07-14

https://ketanbhatt.com/db-concurrency-defects/

leveldb pdf 已经读过了。记录一下

https://yuerblog.cc/wp-content/uploads/leveldb%E5%AE%9E%E7%8E%B0%E8%A7%A3%E6%9E%90.pdf

C++ 中把 lambda 优雅地转化为函数指针 · Terark/terarkdb Wiki

https://github.com/Terark/terarkdb/wiki/C%EF%BC%8B%EF%BC%8B-%E4%B8%AD%E6%8A%8A-lambda-%E4%BC%98%E9%9B%85%E5%9C%B0%E8%BD%AC%E5%8C%96%E4%B8%BA%E5%87%BD%E6%95%B0%E6%8C%87%E9%92%88

Read More

python笔记以及遇到的坑

## pyyaml

  • pyyaml会有特殊的字符串转换,比如把yes转换成true,所以必须要把yes用引号括起来,或者定制yaml的构造函数,定制resolver,见参考链接的做法。

    • 修改意见:主动引号括起来。或者换名字。定制resolver杀鸡牛刀
  • pyyaml对于一些key会加引号,当初由于上层应用不是标准yaml库解析,不能解析引号,所以采用了ruamel.yaml这个库,设置指定的dumper可以让字段不带引号,但是这个库的实现有很大问题,建议别用,而且你能搜到该库作者的很多SO网站回答推广,真有你的啊

    • 不要用,出来混早晚要还的。千万别取巧
  • eventlet 0.25版本,会依赖dnspython库,这个库不能用2.0版本,接口不兼容

    • 解决方法 固定dnspython在1.16或者升级eventlet到0.25.2以上

xml

之前以为xml库难用,其实是我不理解xml

hdfs的配置文件格式xml ,我需要解析一个配置项,改值

  <property>
      <name>dfs.client.failover.max.attempts</name>
      <value>10</value>
      <description>
      if multiply namenodes are configured, it is the max retry times when the dfs client try to issue a RPC call. default is 75.
      </description>
  </property>
  <property>
      <name>dfs.ratelimiter.enabled</name>
      <value>false</value>
      <description>
      ratelimiter enabled or not.
      </description>
  </property>
  
  <property>
      <name>limiter.bandwidth</name>
      <value>62914560</value>
      <description>
      the limited highest bandwidth.
      </description>
  </property>
  
  <property>
      <name>limiter.iops</name>
      <value>60000</value>
      <description>
      the limited highest iops.
      </description>
  </property>
  

主要是限流的改动,全去掉

依据我之前使用json yaml的经验,都是kv型的,怎么也改不了value字段的值

部门高手写了这么段代码,真暴力

xml是树型的,都是子节点,也就是说上面匹配到了text,那下一个肯定是value字段。。。

我之前的考虑就是奔着value字段改的。笨比了。

  import sys
  import xml.etree.ElementTree as ET
  
  tree = ET.parse('hdfs-client.xml')
  root = tree.getroot()
  
  found = False
  for child in root.iter():
      if child.text == 'dfs.client.failover.max.attempts':
          found = True
          continue
      if found:
          child.text = "111"
          found = False
          break
  
  
  tree.write("hdfs-client.xml")
  
  • xml真是太让我头疼了

进程连接不上

  • 网络问题
  • 进程卡死

不要很自信的说网络问题。自己模块写的有问题进程卡死也是有可能的

Python核心语法

  • 共享引用 在原处更改

is == 区别

  • 小的整数和字符串缓存复用了 sys.getrefcount(1)

  • 函数
    • def 生成函数对象并复制给函数名 lambda直接返回函数
    • yield 返回一个结果对象,保存上下文
    • global 模块级变量 nonlocal 类似global,用于闭包
    • 闭包,有点像c++里的函数对象 python中类实现__call__(self)也行,书上说这种写法过于重型
  • 参数
    • 传参是引用还是传值 In-Place Change
    • 避免 主动传值[:],传tuple
    • 任一参数*pargs kargs pargs是元组 **kargs是字典,用来解包 引申-》Keyword-Only 用来指定元组和字典。单独使用做占位参数,则需要调用方保证指定所有入参(a=8这种)注意必须是最后一个参数
  • 再谈函数
    • map(functor, iterable-obj) std::for_each filter std::remove functools.reduce std::acc,
    • 迭代,next()语法糖
      • yield,生成器,for,range这些都是生成器函数
      • 生成器表达式
      • 可迭代对象
  • 模块
    • import from from 危害,模块冲突
    • import 决定将__name__ = ‘main‘解释成模块还是函数
    • 运算符重载
    • __str__
    • __repr__
    • 继承,真正意义上的接口。不会调用基类构造函数
from abc import abstractmethod
@abstractmethod

__getitem__ 买一送一

_iter__

__next__

__del__

__getaddr__ 属性钩子

__slot__

  • 装饰器与元类
    • 类做装饰器
    • 函数装饰类 元类
class tracer:
  def __init__(self, func):
    self.func = func;
  def __call__(self,*args):
    self.func(*args)
  • 异常
    • try except finally
    • raise assert
    • with as
      • with 环境管理协议 enter exit
      • 主动释放with内资源。包括多线程的锁条件变量之类dir

ref

  • https://stackoverflow.com/questions/34282703/yes-or-no-dumping-as-yes-or-no-in-pyyaml
  • https://github.com/eventlet/eventlet/issues/619

Read More

(译)Beyond Relational Databases:A Focus on Redis, MongoDB, and ClickHouse


percona的什么白皮书,我看就是一堆吐槽

关系型数据库不是万金油,用错反而是瓶颈

数据模型万金油,反而限制了扩展能力

sql好用但是不够灵活,json人人爱

ACID很重要,但是代价也很大,这也是关系型数据库的采用点

由于保证事务可靠,也就限制了扩展能力,数据模型简单不要求事务,上内存kv数据库

mysql也能存大数据,但是能存不能用,没啥意义,所以去掉索引,去掉关系限制,列式数据库诞生了


KV数据库

最开始的目的是做个数据库前端无状态缓存

要快,一般都是hashtable。不是为了替代关系型数据库,只是一项中间件技术

后来KV数据库发展成有简单协议的有命令有状态的服务了。不得不提redis

个人认为 redis能打败memcache,社区好,功能性强,memcache就是单纯的做无状态中间件。这种东西mysql内部也做小型cache,比如2Q啥的。不如一个组件强。但是组件本身也要考虑淘汰以及热点击穿的问题。这就是另一个话题了

典型代表redis提供了一些很好的特性,能让业务更简化,比如TTL, list,比如lua支持,LRU淘汰策略,多key事务,阻塞命令等等

做mysql前端最好不过,做个纯粹的数据库也可以(不落盘不停机)


文档数据库

最早来自邮件存储需求

json对象,sparse index 不存在的key就不要,非常灵活

灵活模式不等于没有模式

典型代表 mongodb 不止提供文档接口,还提供了分片管理,方便水平扩展,加钱上机器就行了

还有一些牛逼特性,比如聚合动作方便map-reduce ,geo相关功能,以及可插拔引擎(wiretiger/rocksdb)

劣势

嵌套表效率低

多表join查询

多表事务


列式存储

只要几列数据为什么不用覆盖索引?

  • 查询灵活难道要每一列都建索引吗?不现实
  • 插入要改动索引,复杂度爆炸延迟爆炸

作者没用Cassandra和hbase举例,而是用了clickhouse

  • 兼容大多数SQL
  • 也有索引,针对MergeTree引擎,支持主键,支持range查
  • Dictionaries 查表不用join
  • 低延迟,查询不用担心阻塞
  • 近似估计等等特殊特性

对于读敏感的大数据集,十分好用

OLTP


ref
  1. https://learn.percona.com/hubfs/ExpertOpinion/Beyond%20Relational%20Databases.pdf

Read More

改造glog 提供日志轮转


这个是同事的修改经验,写的挺有意思的,我直接抄过来了

glog是写日志的。选型pika使用,没改。存在的弊端

  • 没有日志删除。最新glog是按照日志轮转的,而不是按照个数/大小轮转
    • glog支持按照大小来切割轮转,但是不支持清理,清理,一个unlink的事儿。
  • 各种日志级别的信息是区分保存的,对于查看来说很不方便

我的同事在这两点上根据pika已有的结构来进行优化,优化的很巧妙:

  • 加上日志个数的glog接口,暴露出来,也就是实现一个接口来unlink
    • 对应的,所有的日志名字要保留到一个数组里。那这个数组的更新也要加锁
      • LogFileObject::CreateLogfile 更新数组,新增接口里改数组
    • 不能频繁检查。放到epoll时间时间里,定时触发
  • 对于第二点,在LogFileObject::Write里有具体的格式,level,去掉就行。LogDestination::FlushLogFilesUnsafe里去掉不同level的flush,改成一个

LogFileObject是具体的操作 LogDestination是底层具体的写入,会持有LogFileObject对象,所有接口从LogMessage暴露

总之挺巧妙的。学习一波经验

ref

  1. https://github.com/google/glog

Read More

改造pika如何去掉key锁


这个是同事的修改经验,虽然是针对业务而言的,但是这个思路十分的降维打击,我直接抄过来了

现有模型是slot-proxy-shard结构,上层有代理来转发,shard节点,也就是pika,只负责一部分数据

但是pika本身是有key锁的

比如https://github.com/Qihoo360/blackwidow/blob/ae38f5b4c5c01c7f8b9deec58db752e056659264/src/redis_lists.cc#L273

Status RedisLists::LInsert(const Slice& key,
                           const BeforeOrAfter& before_or_after,
                           const std::string& pivot,
                           const std::string& value,
                           int64_t* ret) {
  *ret = 0;
  rocksdb::WriteBatch batch;
  ScopeRecordLock l(lock_mgr_, key);
  std::string meta_value;
  Status s = db_->Get(default_read_options_, handles_[0], key, &meta_value);
  if (s.ok()) {
    ParsedListsMetaValue parsed_lists_meta_value(&meta_value);
    if (parsed_lists_meta_value.IsStale()) {
      return Status::NotFound("Stale");
    } else if (parsed_lists_meta_value.count() == 0) {
      return Status::NotFound();
    } else {
        ...

前面已经有一层proxy转发了,这层转发是根据hash来算还是根据range来算不重要,重要的是到计算节点,已经缩小了key范围了,还要加锁,这层锁是可以优化掉的

  • 保证落到这个db的key的顺序,也就是说,相同hash/range用同一个连接,保证了命令的顺序,就不会有锁的问题,锁也就可以省掉。从上层来解决掉这个锁的问题
    • shard节点的命令处理线程,要保证hash/range相同的用同一个连接线程工作。多一点计算,省掉一个锁。

pika单机版,用的是同一个db,同一个db是很难去掉key锁的。要想应用上面的改造,也要改成多db模式,把db改成slot,然后根据slot划分线程,然后根据线程来分配命令,保证命令的顺序,省掉锁。

省掉key锁的收益是很大的。尤其是一个命令里有很多次get,get很吃延迟,导致锁占用很长,导致积少成多的影响


Read More

rocksdb涉及到关闭开启的时间优化


这个是同事调参的经验,我直接抄过来了

不少都是经常提到的

rocksdb配置:

  • compaction加速设置compaction_readahead_size 很常规。值可以改改试试,16k 256k都有
  • wal日志调小 max_manifest_file_size, max-total-wal-size
  • close db的时候停掉compaction
    • rocksdb里有compaction任务,可能还会耗时,能停掉就更好了
  • close会主动flush flush可能触发compaction和write stall。先跳过
  • open会读wal恢复memtable,所以最好不要有wal,close的时候刷掉
  • targetbase和放大因子要根据自身的存储来调整 比如写入hdfs,设置60M就比较合适,不会频繁更新元数据

打开rocksdb文件过多 GetFileSize时间太长

  • 看到一个PR https://github.com/facebook/rocksdb/pull/6353/files 6.8版本在open阶段规避调用 GetFileSize

  • 我们这边同事的解决方案是hack OnAddFile调用的地方,改成多线程cv来添加。

这两个优化点位置不一样,一个在打开 恢复校验阶段,一个在打开阶段,这个打开阶段OnAddFile有GetFileSize,所以在OnAddFile之前,调用一把查文件大小,避开GetFileSize

    std::vector<LiveFileMetaData> metadata;

    impl->mutex_.Lock();
    impl->versions_->GetLiveFilesMetaData(&metadata);
    impl->mutex_.Unlock();

后面OnAddFile阶段就不用查size了,通过这里拿到的metadata,但是有的文件查不到,这里,原生rocksdb用的是GetFileSize,同事是用多线程异步去查,相比原生一个一个查能加速一点


Read More


学习/探索mongo


ppt地址 ,资料都是整理

macos上安装和演示

#安装
brew tap mongodb/brew
brew install mongodb-community@4.4
#拉起
brew services start mongodb-community@4.4
#停止
brew services stop mongodb-community@4.4
# mongo shell
mongo 127.0.0.1:27017

mongo 和sql对应概念 区分

SQL术语/概念 MongoDB 术语/概念
database database
table collection
row documentBSON document
column field
index index
table joins (表联接) $lookup, embedded documents (嵌入式文档)
primary key 指定任何唯一的列或者列组合作为主键 primary key 在 MongoDB 中, 主键自动设置为 _id 字段
aggregation (如:group by) aggregation pipeline (聚合管道)参考:SQL to Aggregation Mapping Chart
SELECT INTO NEW_TABLE $out 参考: SQL to Aggregation Mapping Chart
MERGE INTO TABLE $merge (从MongoDB 4.2开始可用) 参考:SQL to Aggregation Mapping Chart
transactions transactions

二进制对应关系

  MongoDB MySQL
数据库服务端 mongod mysqld
数据库客户端 mongo mysql
复制日志 oplog binlog
恢复用日志 journal redolog
最新 oplog 时间戳 snapshot 状态
t0 snapshot0 committed
t1 snapshot1 uncommitted
t2 snapshot2 uncommitted
t3 snapshot3 uncommitted

ref

  • https://www.runoob.com/mongodb/mongodb-osx-install.html
  • https://aotu.io/notes/2020/06/07/sql-to-mongo-1/index.html

Read More

^