golang的sql.DB的一些注意事项及读写锁的总结
来源:互联网 发布:淘宝流量分配 编辑:程序博客网 时间:2024/06/05 23:46
最近在写一个用于存储protobuf配置的配置管理服务,业务逻辑不难,2天就搞定,但是后续bug不少,也踩了很多坑,在这里记录下。
首先,一直以为golang内的sql模块是单链接的,所以一开始在每个goroutine内都open了一个DB,并写了一个连接池进行管理。后续发现是多此一举,白白写了好多代码。golang的sql模块自带连接池功能,在执行sql语句的时候才会分配连接,执行完毕后归还给连接池,所以假设用golang的sql模块,一个程序一个DB就行了。
既然有连接池的支持,那么也要注意千万不要泄露连接池的连接。假设你采用Query来执行查询语句,那么会返回一个sql.Rows结构,这个结构会占用一个连接,只有在遍历完才会自动关闭,所以最好是获得了Rows后执行一次Rows的Close方法,多次Close是没事的。
然后,因为被上级否定了使用transaction的想法,只能在程序内进行事务控制。一开始整个sql执行model共享一个读写锁,在执行性能测试的情况下,读的tps在3k左右,性能还行,可是写却只是200。这是无法接受的,后来仔细分析了下代码,在写前面锁了写,那么并行的几个routine会等待占有锁的那个routine写入完毕才会有第二个routine进行写操作,就等于白白的排队了,而测试用例是insert新的记录而已,不会有冲突的问题。现在想想一个锁虽然写起来方便,但是性能影响很大,于是今天写了一个新的读写锁管理器,绑定特定的key,每一个key在当前key的锁被占用的情况下,会返回被占用的锁,并且将引用计数值+1,假设没有对应的锁,则返回新的锁。释放锁的时候,判定当前key的锁的引用值,假设已经为0了,说明没有被其它routine进行锁wait,则销毁这个锁,否则引用计数值-1。
这样的话,将不同的sql生成一个key,采用这个key来进行写冲突管理,当两个sql有相同的key的时候,则会进行锁竞争,假设key不相同,则不会有竞争。同时采用引用计数来避免读写锁的泄露,对长期稳定运行服务器有好处。
读操作的话,则当前没有写锁的情况下,则直接进行读取,所以读的性能不会有很大的影响。
在这个新的锁的设计下,tps从200提升到了1200,算是可接受的范围了。这个方案的关键点在于key的生成,在于提取每个sql操作影响的行,只要能得到这个key,则生成读写锁将十分方便。
- golang的sql.DB的一些注意事项及读写锁的总结
- setting的一些总结及settings.db字段含义
- MYSQL查询SQL的注意事项和一些技巧总结
- 关于dB单位的一些总结
- 搭建golang的beego注意事项
- GBase编写sql的一些注意事项
- sql查询语句的一些注意事项
- 关于SQL优化的一些注意事项
- 编写sql语句一些关键词的注意事项
- golang的小总结
- 大神总结的一些android4.4注意事项
- 序列化的一些注意事项及建议
- Hadoop搭建的一些注意事项及解决方法
- typedef的一些用法及注意事项
- Cookie的一些API及注意事项
- golang thrift 总结一下网络上的一些坑
- S3C2440读写sd卡的一些总结
- golang sync包的读写锁RWMutex的使用
- java疯狂讲义学习过程学习笔记5.8.2利用组合实现复用
- Git和SVN之间的五个基本区别
- Angularjs 验证码60秒发送
- Java Executors(线程池)
- 初识ubuntu Snap(一)Snap应用于Ubuntu 16.04LST
- golang的sql.DB的一些注意事项及读写锁的总结
- 简历网站_成果_1
- L2-008. 最长对称子串
- 传智播客:一道算术题看网络营销模式变迁
- IOS中的单例模式(Singleton)
- 如何测试agent程序
- 分页管理系统计算题 (在某个请求分页管理系统中,假设某进程的页表内容如下表所示)
- 利用MJExtension处理OC里"id"关键字
- 本地事务和分布式事务工作实践