首页 文章 精选 留言 我的

精选列表

搜索[思考模型],共10004篇文章
优秀的个人博客,低调大师

对incaseformat蠕虫事件一些思考

昨天incaseformat蠕虫病毒在全国爆发,各大安全厂商相继发布公告,安全产业似乎又迎来了新的发展机会...... 全国的安全厂商都在报道这个蠕虫事件,估计有一个人会坐立不安,那就是这个病毒的作者,至于原因,大家应该都懂的(开个玩笑)...... 其实这个病毒早在2009年就开发出来了,作者估计本来是想在愚人节的时候闹一下,也没想因为一个BUG,这款病毒在12年后会在全国爆发,引起这么大的动静,估计昨天作者看到了各大安全厂商的报道,才知道自己的“作品”受到了这么大的“欢迎”,也许这位作者已经成为了”某个安全厂商“的安全”砖”家,也许这位作者已经转行了,也许这位作者还在从事”黑产“活动,大家自由猜想吧,虽然这款病毒本身没有赢利,然后这也可以按破坏计算机信息系统罪来处置了,这次病毒的影响不亚于当年的”熊猫烧香“,而且两款病毒的技术含量也都很低,这款病毒相比”熊猫烧香“,可能技术含量更低一层了,”熊猫烧香“还多了几个感染、下载、自传播模块,这款病毒是型典的破坏型蠕虫病毒,其实这类病毒在十几年前非常流行,当时有很多U盘蠕虫病毒,十几年过去了,没想到这样的一款简单的蠕虫病毒又在全国有这么大的影响,这究竟是什么原因引起的呢? 笔者从05年开始研究病毒,到现在差不多十几年了,从PC时代(Windows/Linux)病毒到后面研究移动端(安卓,IOS)病毒,OSX(Mac)病毒,以及最近两三年新起的IOT僵尸网络病毒等,从业十几年基本上各个平台的恶意软件都有深入研究,这几年做To B,主要从事PC病毒的研究,基于Window/Linux两大平台,好像又转了一个大圈回来,笔者常常会听到一些人说“现在没有病毒了”,我用“mac"安全,Mac没有病毒,"Linux系统也没有病毒"之类的,其实就是不懂病毒,不懂安全这个行业吧了,不管是几十年前,还是现在计算机病毒一直存在,并没有减少,反而越来越多了,只是因为某些原因关注的人少了,至于原因我后面讲吧,从几十年前DOS平台上COM感染型病毒,到后面Window系统以后的蠕虫病毒,感染型,远控,木马,后门,下载者,DDOS病毒,直到现在最近几年比较流行的挖矿病毒,勒索病毒,IOT僵尸网络病毒,APT特马等等,可以说计算机病毒一直存在,从未消失过,只是在不同的时代,表现形式和攻击方式会有不一样,因为黑产的赢利模式会随着时代的变化而变化,以前大多数黑客写病毒就是为了”好玩“,”炫技“,现在大多数黑客组织只有一个目的就是”赚钱“,还有一些高端的黑客组织会成为国与国之间进行网络安全战争的”特种部队“,这种高端的黑客组织会基于政治和军事目的定向的攻击其他国家的重要政企单位,获得核心数据。 其实蠕虫类,感染型类的病毒,在现在基本没啥意义了 ,因为他们只能造成一些破坏性动作,而且随着操作系统的升级大部分蠕虫,感染型病毒已经失去了作用,只能在一些老的操作系统上运行,基本没啥危害了,现在主要的危害就是勒索病毒,挖矿病毒,僵尸网络和APT特马等。 上面简单给大家科普了一些病毒方向的知识,下面来讲讲这次蠕虫事件引发全国”烘动“,可以从这次现象,看到哪些本质的东西。 通过这次事件,可以说明现在企业病毒真的是太多了,先不要说现在新型窃密,远控,后门和APT特马病毒了,就是很多老的病毒都还没有清理干净,十几年前的很多旧病毒家族,还在国内很多企业中安安静静的”躺着“,那为什么会造成这种形象呢?难倒这些病毒安全厂商就没有办法,其实很多老的病毒,安全厂商都是可以完全清理的,包含各种感染型病毒,蠕虫病毒,只是现在关注病毒的人少了,做病毒研究的人少了吧了,为什么会导致现在这种形象?一个十几年前的蠕虫病毒,究竟能在全国引起这么大的动静,安全圈一直在炒作:大数据,数据安全,然后就是说:传统安全没用之类的,其实这次的安全就是一次”传统“安全的很普通的一次事件,这样的事件,在十几年前的安全厂商病毒研究人员那里,基本上天天会遇到,每天都会分析各种蠕虫病毒,感染型家族样本,以及后面的鬼影病毒等,然而在十几年后的今年,一个十几年前的蠕虫病毒,究竟能引起这么大的影响,to C安全的春天是不是要回来了,哈哈哈哈。 咱先不说老的那些病毒了,什么蠕虫 ,感染型病毒的,其实现在各种新型的病毒很多,为什么现在研究病毒的人少了?大家为啥不关注了,我来说一下自己的一些观点吧。 很多年以前的安全厂商其实大家重点研究的就是病毒,反病毒工程师是每个安全厂商必不可少的职位,反病毒工程师的工作就是每天捕获最新的病毒样本,然后进行逆向分析,提取相应的特征,集成到杀毒软件的引擎里面,这样的日子过的充实而有激情,当年的杀毒软件是付费的,然而突然之间出现了一家厂商免费提供这种服务,于是其他厂商的日子就过的越来越艰难了,然后这家厂商在做大之后,就通过流量广告等等来赚钱,后面也不做安全,去做了其他很多事情,导致其他厂商的安全从业者纷纷转行了,因为”安全“不赚钱,大家都要生存,只能转行了,能坚持做安全的很少很少了,这就导致现在研究病毒的人越来越少了。 研究的人少了,自然就会认为病毒少了,因为发现"问题"的人少了,"问题"就自然没有了,然后很多人就会说“现在没有病毒了”,再加上一些新型的名词开始炒作,各种新型的产品的推出,大数据,AI加入进来,后面更多的人开始去做大数据,做AI,其实这些人大部分人根本不懂安全,也不懂计算机病毒,然后这批人就会说这是传统安全,我们要做“新型”安全,就变成了现在这个局面,反病毒工程师这个名词在国内基本消失了,现在大家都叫安全分析师,其实真正的安全分析师不就是以前的反病毒工程师吗?然后现在又推出数据安全工程师之类的,总之各种新的名词出现,整个安全行业又重新燃起了希望,to c安全不赚钱,很多以前的安全从业人员,要么去做其他安全了,要么就直接转行做别的了,还有一些做了管理也基本不研究安全技术了,现在又有很多新型的病毒出现,大家就把希望寄托在了大数据,AI安全上面,这样就导致”传统“安全的人越来越少,也就是研究病毒的人越来越少了,很多”新型“的安全研究人员,不太懂病毒,对病毒不了解,也不认识病毒,其实也怪这款病毒太老了,他们没机会认识。 其实不管是to c安全,还是to b安全,安全问题一直没有变化,只是之前关注的人少,现在关注的人多了吧了,就像我说的,现在还有多少企业被攻击监控植入了木马后门,是一个未知数,企业的数据一直被黑客组织监控并获取,安全的路还很长,一次病毒的爆发仅仅是安全问题的冰山一角,其实还有更多的新型病毒被黑客组织研究,用于对一些重要的政企单位进行定向攻击使用,安全的路还很长,路漫漫其修远兮,吾将上下而求索。 基于这次病毒爆发事件,谈谈自己的一些感想,也给大家普及一下病毒的相关知识,借用一句话:这是一个最好的时代,也是一个最坏的时代,历史总是惊人的相似,各种病毒横行,安全未来可期,机会无处不在。

优秀的个人博客,低调大师

ceph设计哲学与一些思考

ceph最终要的设计哲学是:一切都可以被扩展。无论是在上层组件设计,还是底层硬盘的设计上,ceph都要求每个组件都能做到水平横向扩展。当某些资源不够用时,都需要能添加硬件的方式来提升集群的可用资源、性能。 为了践行这个设计哲学,ceph在设计上遵循了2大理念: 一切皆对象 一切皆crush ceph的文件存储、对象存储、块存储的三种存储形态都建立在名为RADOS的对象存储层。上层存储形态中的文件都会被分割为一个个rados对象存储在对象中。ceph并不提供中心元数据服务器来索引所有对象,而是基于对象、存储池、存储桶的名称,配合crush算法来实现对象的定位。每个文件会分割成一个个rados对象,并且通过crush算法,分发到不同的osd上去,从而将上层IO流量均匀地分配到每个集群节点上去。 Crush算法 在介绍crush算法之前,还需要介绍两个概念: 1. PoolCeph对PG做的逻辑上的划分。每类存储都有其对应的默认存储池,比如RBD的默认存储池为rbd, RGW的对应存储池为default.rgw.buckets.data, CephFS的对应存储池为cephfs。也就是说,不同的RADOS上层来的数据,最终会落到不同的Pool中,由此来更好的管理数据。 PG(placement group) 一些对象逻辑上的合集,也是Pool最基本组成单位,是实现冗余策略,数据迁移、灾难恢复等功能的基础。可以向上接受、处理客户端请求,转化为能被ObjectStore理解的事务,是一个对象落到OSD上的最后逻辑载体。 因此可以看到,一个文件从客户端写入,到最终落盘,以对象存储为例,会经历以下过程: rgw object -> rados object -> pool -> pg -> osd 而一个rgw对象被映射成一个rados对象,一个rados对象被映射到PG,一个PG映射到一个OSD中,都需要借助哈希算法,这三次哈希转变,也就是crush算法的核心。 rados对象寻址方式 当一个对象被分割成一个rados对象后,这个rados对象会跟着pg这个逻辑概念,最终被写入到若干个osd中去。那么在osd上,这个对象如何被定位? 这边需要讨论一个概念ObjectStore。ObjectStore是ceph中的底层,介于rados层和硬盘之间,目前用的比较广泛的有2种:FileStore, BlueStore。 # FileStore使用linux文件系统作为后台,提供了文件日志功能,当rados对象通过message queue写入时,首先会写入这个file journal(wal), 然后再写入文件系统。但是文件系统本身也会做一次file journal,那么就有2次的journal写浪费。(所以就有了后面的bluestore) 由于filestore本身是文件系统,那么raodos对象会在其目录结构中存放。filestore的目录结构生成有一定的规律。比如一个rados对象通过哈希计算后,其通过对象名称的哈希逆序去组织目录,可以很方便的找到文件所在。 //我们通过osd map功能来定位一个rados对象所在的pg, 同时发现这个pg所在的osd编号为291, 147, 111。其中osd 291为主副本所在位置 [~]# ceph osd map default.rgw.buckets.data 16f6d89a-ebc2-4b84-93cc-763b1440c57b.236665132.18_123456qwer osdmap e40580 pool 'default.rgw.buckets.data' (15) object '16f6d89a-ebc2-4b84-93cc-763b1440c57b.236665132.18__shadow_.W2fSlp2edVHI8V075Vmz9UojvQcMhwd_2' -> pg 15.3a9a6a5a (15.2a5a) -> up ([291,147, 111], p291) acting ([291,147, 111], p291) //通过osd find来找到这个osd 291所在的节点ip [~]# ceph osd find 291 { "osd": 291, "ip": "10.125.137.5:6838\/304721", "crush_location": { "copy-set": "cs01", "host": "d-j01-osd-04", "host-group": "cs01-hg01", "root": "apple" } } //登录该节点:DIR按照15.2a5a逆序 [~]# ls /var/lib/ceph/osd/ceph-291/current/15.3a21_head/DIR_A/DIR_5/DIR_A/DIR_2/ | grep 16f6d89a 16f6d89a-ebc2-4b84-93cc-763b1440c57b.236665132.18__shadow_.W2fSlp2edVHI8V075Vmz9UojvQcMhwd_2 # BlueStore为了提高Ceph的写入性能,社区开发了BlueStore这一存储后端,让数据绕开了本地文件系统直接裸盘,从而解决了Journaling of journal问题。BlueStore采用RocksDB来管理对象元数据,因此为了跑RocksDB,BlueStore内部有一个微型用户态的文件系统-BlueFS。得益于RocksDB,Ceph可以很方便的获取和枚举所有的对象, Rados对象在硬盘中的寻址也依赖这个RocksDB。 对象存储索引方式 虽然在上文提及,ceph并没有一个中心元数据服务器来记录所有对象的信息,但是ceph仍然为每个存储桶绑定了一个索引,该索引以omap的形式记录了这个存储桶下的对象元数据信息。当RGW有list请求过来时,那么就会去通过这个索引去获取这个存储桶下所有对象的名称以及其元数据。另外,当集群使用多数据中心同步、存储桶审计功能时,都需要依赖这个功能。而每个存储桶的索引也是一个rados对象,被存放在default.rgw.buckets.index这个存储池中,最终会存放到这个rados对象对应的osd的leveldb这个kv数据库上。不难想象,如果一个存储桶下面有海量对象的话,这个rados对象会非常大,遍历势必会很耗时,因此ceph支持了索引对象分片(bucket sharding),可以将一个存储桶的索引对象分割成多个分片,然后保存到不同osd上。并且如果索引分片不够大,也可以通过resharding来调整,但是reshard会阻塞这个存储桶的业务,并不是很理想。ceph采用leveldb在我看来也是对其设计哲学的一种践行。leveldb采用lsm算法,来将多个随机写用类似归并的方式合并成一个大的日志文件,然后顺序写入到磁盘中,大大提升写入性能。但是也牺牲了一定的读性能。更要命的是,ceph的早期leveldb的迭代器设计不好。当有遍历请求来的时候,迭代器会遍历这个leveldb,并且在访问时不断分配内存,直到事务完成,迭代器用完后内存才会释放。因此如果一个存储桶有上千万个对象,那么每次list请求会让这个leveldb所在的osd吃紧大量内存高居不下,会导致osd退出。为了规避这个问题,需要在硬件、软件、使用上都做好准备: 用ssd盘来加速default.rgw.buckets.index存储池 osd所在节点的内存要保证够大 优化ceph的leveldb迭代器实现,在大的事务中,要分段迭代,完成一定数量的遍历后,要记录当前位置,然后释放这个迭代器,释放内存,重启一个新的迭代器,由此来控制内存的使用 缺憾 1.list会比较慢,因为对象存储这边没有目录树的概念,如果要获取某个虚拟目录下的孩子信息,那么需要遍历以这个虚拟目录地址为prefix的所有对象,来后做一遍过滤。2.rbd目前只支持cow,未来希望还可以实现row

优秀的个人博客,低调大师

关于服务器性能排查的思考

服务器上性能排查的经验不多,这里算对以往经验的一个总结吧! 服务性能排查一般就两种:高内存占用或高CPU占用,需要具体问题具体分析。比如应用程序高内存占用,可能因为大文件读取、频繁IO,内存消耗频繁,导致频繁GC,进一步占用内存和CPU;比如应用程序高CPU占用,可能在执行大任务计算,或者死循环、卡死,或者不断超时、重试(活锁是容易占CPU的,死锁和饥饿是容易占内存的,因为资源不释放)。 应用进程还活着,但页面出不来、不响应,这种是高CPU,高内存是应用响应慢或者内存溢出、直接死掉。 从这两个方向考虑,比如: 高CPU占用的话,关注一下,是user态占用率高还是sys态占用率高,闲置多少;占用率高的进程是否频繁变动;load平均负载是否过载(超过70%)。如果user态CPU占用率过高,意味着应用在做高耗CPU的任务;如果sys态占用率过高,则意味着内核态的操作比较多比如IO复制;如果占用率高的线程频繁变动,则可能是CPU时间片不断调度,线程唤醒跑一下而后换另一个线程跑,需要看多线程任务是否存在大计算问题,以及线程池设置是否合适等; 高内存的话,关注一下,free可用内存有多少,buff、cache还有多少;swap交换区是否过高,这通常是因为未禁用swap区而内存又不足,导致swap频繁读写,性能低下;sar内存变化曲线,是稳定上升还是高低曲线,前者意味着某个函数存在内存泄漏问题,而后者意味着有某个高内存运算任务在线程池里唤醒重试; 更实际的情形是,应用出现高应用或者高CPU的问题时,你只有30秒到两三分钟来快速定位问题,而后就要马上重启应用,避免影响到正常业务。像高CPU,可能连日志都没有,因为请求没进来,很多时候你都需要去前后dump线程堆栈或内存堆栈,以保留现场方便后续分析工作。成熟的线上环境,一般会有仪表大盘和监控预警,内存或CPU超过阈值你就需要立马去关注了,或应用发布回滚,在线下验证问题。 一般出问题时,首先去看监控大盘,有没有异常告警,看不出问题来再去查看系统层面有没有异常: 通过top或htop命令观察系统的整体情况,很容易拿到占用CPU或内存较高的进程ID; 先通过ps aux | grep [PID]进一步确定是Java进程还是服务器上其它进程; 如果是CPU占用高,通过pidstat查看该进程,然后用perf/trace+PID,抓取CPU消耗栈来找到引发瓶颈的具体的函数名,结合业务代码来分析问题具体在哪儿; 通过ps -mp pid -o THREAD,tid,time 找到具体的线程ID; printf "%x\n" [TID]] 将线程id转换为16进制 如果是内存占用高,通过free命令查看内存的使用情况,然后通过pmap/jmap命令查看进程的内存分布 或是通过vmstat命令查看内存使用的变化趋势,用memleak -a -p [PID]查看内存分配栈,定位到是哪个函数内存泄漏了 如果CPU、内存没问题,就要去看磁盘,通过df命令和iostat命令去查看磁盘空间和I/O情况; load平均负载和CPU使用率是有区别的,一个是单位时间内的活跃进程数,一个是单位时间内CPU空闲时间与总CPU时间的比值。它们之间有一定的联系,比如在CPU密集型应用中,大计算量任务会导致大量的CPU被占用,平均负载升高,而在I/O密集型应用中,不可中断进程的增多会导致平均负载升高,但I/O等待不占CPU,CPU使用率并不一定会很高。 CPU性能排查时首先去查看CPU使用率,比如user用户态较高,则往应用进程的性能问题去排查;如果sys内核态较高,则往系统调用的性能问题去排查。但很多时候,监控告警之后,等你登陆服务器时性能问题已经结束了,这样在线分析就看不出问题了,就需要从load平均负载、sar历史记录去回溯。 写的很粗,关于上下文切换的问题不是很懂,没写进去。如果有不同的意见建议,欢迎拍砖

优秀的个人博客,低调大师

关于规则引擎的选型和疑惑思考

这是一个一些业务开发人员或者架构设计人员经常遇到的困惑: 1、给我推荐一个最简单、易用的规则引擎 1、运营人员觉得之前做的规则引擎不好用,是否可以做一个适合我们使用的规则引擎?不用看懂代码,直接界面表单提交操作。 2、我们的操作者是运营人员,大部分无技术背景,人员还有流动性,所以选型倾向选择可视化易编辑易理解的开源规则引擎。 能否推荐下选型,并说明优缺点 我的观点: 1、你要的可视化易编辑易理解的开源规则引擎是不存在的。 通用的规则引擎只是把原来的java代码转化成了脚本来动态解析执行而已。本质上还是需要写代码,比如要写drools的表达式,如果你的运营人员不懂,并且培训无效那就没有办法了。 2、但是基于规则引擎的业务系统可以做到配置人员无需了解代码。 这个过程首先需要开发人员总结、提炼出目前的N个业务类型,然后针对每个业务类型开发出运营人员需要配

优秀的个人博客,低调大师

【思考】Python声明和定义可以分开么?

本博客共分为四个部分,每一个小部分都可以看作一个独立的小问题,但相互之间又联系紧密。 第一部分: 探究这个问题,还是因为编程的时候碰到了这个错误: 提示tcplink没有定义,tcplink是我自己写的一个给监听到的tcp连接请求分配新线程的函数,不过是写在了下面,就像这样: 如果是C++里面的话,解决这个问题很简单。在文件开头的时候,加上该函数的声明式就OK,这样不仅方便,还能最大限度的保持美观(雾)。但是问题来了,Python里面好像没有声明和定义这一说呀! 到底有没有呢?这个得要从Python脚本的运行机制来看了。 在C++里面,声明是告诉编译器我的程序里将会有这个符号,编译器将声明内容进行记录,在定义处记录入口,分配内存。换言之,由于C++是编译型语言,这就可以对完整的程序进行扫描,进行跨文本域的联系。 然而,Python却不可以,Python是解释型语言,虽然我们自己写的脚本是一个完整文件,但是在给Python解释器执行的时候,依然相当于是把脚本文件里的内容一行一行输入进解释器并执行。这就造成了如果执行的当前语句要调用tcplink,解释器立马会在之前输入的内容中寻找tcplink的定义并执行,如果无法执行则报错。因为有这个机制,直接就导致了不能像C/C++那样,先放个声明式在前面,在把定义放到其他地方。 第二部分: 有些人可能会问,拉倒吧,我编程的时候这样写,funcb在funcc前面,funcb内将执行funcc,为啥运行的时候什么错误都不会报呢? 这就更有的说了,我们先来把这一小段放到Python命令行交互模式下,看结果如何: 对,依然也是什么错误都没发生。那么,根据之前所说,Python解释器是进来一行解释一行,如果无法解释就会立马报错,为什么这里解释器读入了funcc,用户也没有进行funcc的定义,解释器却没有报错呢? 其实,“Python解释器是进来一行解释一行” 这种说法其实还不太严谨。细心的读者能够发现,当在Python解释器输入def funcb():并回车的时候,>>>变成了...,只有在funcb用户定义完成后并确认,才又会回到>>>。一般情况下,用户是输入一行回车,>>>不发生改变,并输出应该有的结果。所以这说明了什么呢?这说明了两点问题: 1.在定义funcb()的时候,用户的回车没有让输入的语句执行。 2.定义完成funcb()向解释器发送回车确认的时候,解释器也没有执行之前定义内的内容。(因为如果执行了,一定会报错,就像下面这样) 新的问题又出现了,所以之前解释器到底执行了什么?答案就是:执行了“定义funcb()”这一个语句。这样,第二部分开头的那个问题,我想大家心里应该有答案了。把第二部分开头的那段程序执行过程画个图来理解,就像这样: 简而言之,如果当前只是执行了“定义XXX”的语句,解释器并不关心你具体定义的内容,此时进来的内容,解释器暂不执行。所以由于之前的funcc()是funcb()内定义的内容,自然不执行,也就无关乎是否此时存在funcc()。但!如果我此时调用funcb,解释器就会转而执行funcb内的具体内容,此时如果funcc()还没有被定义,一定会报not defined的错误!咱们来验证一下: 看来,说的不错。而第二部分开头的代码,在funcc实际被执行的时候,已经获得了完整的定义,故就不会报not defined的错误拉~ 第三部分: 那么,有没有什么方法,能够让我的Python程序看起来更加整洁美观——不让所谓的“主程序”文件内函数太多而显得杂乱呢? 其实,import是个挺不错的方法,稍微熟悉Python的人都明白,import可以引用其他地方的py等模块,还可以用from module import function的形式,单独引入指定模块内的指定函数、类。 甚至!! 对于一个从C++过来的人,真是傻了。Python的import相当于“把import的东西原封不动塞进import处一整坨”,所以由于是在函数定义内import的,所以import的东西只有在该函数内才可使用~然而C++/C的单独#include预处理指令则是做不到的。 等等。是不是错过了什么重要的东西…… 是的,如果import直接导入本文件,是否是可以的呢?如果可以的话,那岂不是之前的例子中,在之前加上: from 本文件 import funca/b/c,就可以实现类似C++函数声明的作用了?万一成功了,那岂不是……真香? 我们来试试: 看来,真香失败。那么,为什么这种方法不行呢?我们来回顾一下第二部分中部那个我自己画的流程图,由于Python解释器是进来一句执行一句,所以这里执行的内容是:导入daliywork中的funcb。执行这一句的时候,funcb没有定义,故导入失败。但必须说明的一点是,“import 文件本身” 是可行的!可见接下来这张演示事例: (坏了,这里又埋下了一个种子,被导入的daliywork里面的导入的daliywork是否产生了执行?如果有,执行的内容显示到了哪里?) 第四部分: 最后一个问题,如果import整个文件自己本身,可不可以实现这种结果呢?(就和只执行定义XXX时解释器不会探究具体定义的内容一样,这种只执行导入整个文件的操作,解释器是否会关心整个文件内的具体内容呢?) 我们再来回顾一下第三部分内关于import一个很直观的解释(但不是很严谨): 好了,有了这个解释,我觉得大部分人心里已经有答案了。测试代码如下,我们直接执行来看一下结果: 异常栈首先提示funca没有定义,指向daliywork第六行,但这个错误又是因为daliywork的第三行import导致的。这是因为import整个文件后,相当于把除了import这句以外的部分,替换到了import本身的地方,然后执行这些代码,这时候,在引入的部分内,执行到funca,发现还是没有进行定义,这时候再报出funca没有进行定义的错误。需要注意,错误内报了funca没有经过定义,并不是报的执行文件中的funca没有定义(因为此时在源文件line3 import这一句就已经抛出异常了,程序已经停在这里了!),而是import的daliywork里面的第六行出现的错误。这一点十分重要,可以用以下的图解进行解释(PS:画图真好用): 虽然引入的内容里,包括了所有的定义内容,但是由于引入的文件也会发生执行,所以依然无法实现我们想要的效果…… 看来,由于Python特殊的解释执行机制,导致了没什么方法可以只把函数的声明提前。以后写代码的时候,还是乖乖要么把定义的函数都放到其他文件通过import module方式导入,通过module.function()形式进行调用;要么乖乖放在要执行该函数的代码的前面吧…… 最后献上一首小诗。 无题 声明定义要分离,Python解释行不行? 千变万化难模拟,绕了一圈空叹息。

优秀的个人博客,低调大师

对缓存击穿的一点思考

前言 缓存(内存 or Memcached or Redis.....)在互联网项目中广泛应用,本篇博客将讨论下缓存击穿这一个话题,涵盖缓存击穿的现象、解决的思路、以及通过代码抽象方式来处理缓存击穿。 什么是缓存击穿? 上面的代码,是一个典型的写法:当查询的时候,先从Redis集群中取,如果没有,那么再从DB中查询并设置到Redis集群中。 注意,在实际开发中,我们一般在缓存中,存储的数据结构是JSON。(JDK提供的序列化方式效率稍微比JSON序列化低一些;而且JDK序列化非常严格,字段的增减,就很可能导致反序列失败,而JSON这方面兼容性较好) 假设从DB中查询需要2S,那么显然这段时间内过来的请求,在上述的代码下,会全部走DB查询,相当于缓存被直接穿透,这样的现象就称之为“缓存击穿”! 避免缓存击穿的思路分析 加synchronized? 如果synchronized加在方法上,使得查询请求都得排队,本来我们的本意是让并发查询走缓存。也就是现在synchronized的粒度太大了。 缩小synchronized的粒度? 上面代码,在缓存有数据时,让查询缓存的请求不必排队,减小了同步的粒度。但是,仍然没有解决缓存击穿的问题。 虽然,多个查询DB的请求进行排队,但是即便一个DB查询请求完成并设置到缓存中,其他查询DB的请求依然会继续查询DB! synchronized+双重检查机制 通过synchronized+双重检查机制: 在同步块中,继续判断检查,保证不存在,才去查DB。 代码抽象 发现没有,其实我们处理缓存的代码,除了具体的查询DB逻辑外,其他都是模板化的。下面我们就来抽象下! 一个查询DB的接口: 既然查询具体的DB是由业务来决定的,那么暴露这个接口让业务去实现它。 一个模板: Spring不是有很多Template类么?我们也可以通过这种思想对代码进行一个抽象,让外界来决定具体的业务实现,而把模板步骤写好。(有点类似AOP的概念) 改进后的代码: 从这里可以看出,我们并不关心缓存的数据从哪里加载,而是交给具体的使用方,而且使用方在使用时再也不必关注缓存击穿的问题,因为我们都给抽象了。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册