老板:把系统从单体架构升级到集群架构!问北

如题,本文针对工作中实际经验,整理了把一个单体架构的系统升级成集群架构需要做的准备工作,以及为集群架构的升级做指导方针。

本文首先分析了单体架构存在的问题,然后介绍了集群架构(好处、注意的问题、架构图),接着分析了目前系统的主要功能以及集群后需要做哪些调整,然后对集群架构涉及的技术做横向对比,最后确定技术选型。从这几个方面介绍了从单体架构到集群架构的改造过程,希望对你有帮助。

单机存在单点故障的隐患

Jvm内存频繁在某时段报警

项目目前的架构是单体垂直架构,只有一个服务节点,存在一些问题,以下是对存在问题的分析:

1、服务可用性差

2、服务性能存在瓶颈

单机所能承载的读写压力、请求数都是有限的,当系统业务增长到一定程度的时候,单机的硬件资源将无法满足你的业务需求,增加服务器配置所带来的的性能提升与昂贵的成本不成正比,性价比不高。

3、不可伸缩性

单体架构的弊端之一就是伸缩性不强。随着需求和负荷的增长,单体架构的性能满足不了现有需求时,增加服务器资源的手段收效甚微,服务的性能可扩展性低是单体架构的致命缺点。

4、代码量庞大,系统臃肿,牵一发动全身

随着业务功能增加,系统代码量不断增加,系统变得庞大而臃肿,开发人员修改一处代码往往担心会牵涉到其他功能。

据统计,项目后端代码行数高达12万行(Java),前端代码行数高达34万行(html+css+js),日常维护、版本迭代、发版上线的成本也相应增加。每次项目上线前都要对系统进行回归测试,上线时要把项目进行全量打包发布,上线后监测系统日志是否正常,担心会不会影响其他功能模块。

可规划系统拆分。

1、单点故障单机部署很容易出现服务挂了之后,没有备用节点,从而影响用户使用。单机对外提供服务,风险很大,服务器任何故障都可能引起整个服务的不可用。

2、性能瓶颈单机遇到资源瓶颈时,要想支持更大的用户量,性能有较大的提升,一般是优化业务和增加服务器配置。然而这么做只能是杯水车薪,成本巨大并且效果非常有限。而集群部署通过部署多个服务节点水平扩展服务的性能,成倍的增加服务器性能,而且支持动态扩展。

2、吞吐量。增加吞吐量,并发量,支持更大的用户量。

3、易扩展。也叫可伸缩性,可伸缩性体现在节点数量的调整,在预知流量增大的情况下,可以提前增加节点。

1、负载均衡问题。

请求应该由哪个节点处理?--应用集群需要有一个组件来管理请求的分发。--常见的如Nginx

2、session失效问题。

--集群环境下session需要同步。方案:Tomcat自带的session复制、springsession+redis实现分布式session

3、定时任务执行问题。

定时任务分配给哪台机器执行?

确保不会重复执行,最简单的办法就是定时任务拆分出来,只部署一个节点。方案:分布式job框架、分布式锁实现job的分配。

4、缓存一致性问题。

原来缓存在本地的数据,需要保证数据的一致性,实现共享,只保存一份。(比如两个节点各缓存了一份不同版本的数据,就会出现同一个页面刷新,交替展示不一样的数据直到缓存失效)。--Redis

站点部署多个节点,集群前面架设Nginx做负载均衡,Tomcat之间通过Redis实现session共享。

解决方案:

1.不要有session:大家可能觉得我说了句废话,但是确实在某些场景下,是可以没有session的,在很多接口类系统当中,都提倡【API无状态服务】;也就是每一次的接口访问,都不依赖于session、不依赖于前一次的接口访问;

2.存入cookie中:将session存储到cookie中,但是缺点也很明显,例如:每次请求都得带着session;session数据存储在客户端本地,是有风险的;

3.session同步:多个服务器之间同步session,这样可以保证每个服务器上都有全部的session信息。不过当服务器数量比较多的时候,同步是会有延迟甚至同步失败;

4.粘滞会话:使用Nginx(或其他负载均衡软硬件)中的ip绑定策略,同一个ip只能在指定的同一个机器访问,但是这样做风险也比较大,而且也失去了负载均衡的意义;

5.session分布式存储:把session放到Redis中存储,虽然架构上变得复杂,并且需要多访问一次Redis,但是这种方案带来的好处也是很大的:实现session共享,可以水平扩展(增加Redis服务器);服务器重启session不丢失(不过也要注意session在Redis中的刷新/失效机制);不仅可以跨服务器session共享,甚至可以跨平台(例如网页端和APP端)。

系统中权限控制基于数据库权限表实现,无需调整。

梳理出哪些业务功能会受到影响?影响包括变量的使用。

通过梳理系统中代码,发现目前系统中对数据的缓存其实是缓存在本地jvm内存中的,自己实现了一套缓存过期机制,但是这种方式并未对缓存占据内存大小进行控制,这样缓存使用的内存有无限增长的可能,甚至导致内存泄漏。

这些变量用做本地缓存,存在jvm中,若集群部署,则在各自的jvm进程中都会存一份,不能共享,可能存在如下问题:第一次请求,由服务器A处理,其查询后存了一份数据V1,第二次请求由服务器B处理,刚好数据发生变化,查询后存了一份数据V2,后续请求如果均匀的分发到AB服务器,那么用户看到的数据将一会儿是V1一会儿是V2(在缓存未过期时),这样就造成了数据不一致。

集群部署的初衷是解决JVM内存频繁告警,内存告警的原因可能是定时任务比较耗内存,本次讨论不展开jvm内存频繁告警的问题。另外,系统一旦做集群部署就需要考虑集群环境下的定时任务不能重复执行。

1.代码拆分

2.任务防重复执行

如果将定时任务代码拆分且集群部署或不拆分(原系统集群部署),那么定时执行的任务,需要控制同一个任务触发时只有一个节点执行,可用分布式锁实现、或quartz框架自身支持。

分布式锁方式:执行前先尝试获取锁,获取到则执行,否则不执行。缺点:需引入分布式锁,修改现有业务代码。

quartz自带集群功能的支持:需修改配置文件,同时数据库导入quartz官方的11张表。优点:自带功能,对外透明,不需要改代码,对现有业务影响较小。

在服务器集群中,需要有一台服务器充当调度者的角色,用户的所有请求都会首先由它接收,调度者再根据每台服务器的负载情况将请求分配给某一台后端服务器去处理。

那么在这个过程中,调度者如何合理分配任务,保证所有后端服务器都将性能充分发挥,从而保持服务器集群的整体性能最优,这就是负载均衡问题。

负载均衡种类:DNS、硬件、软件

参考:

负载均衡种类及优缺点

高并发解决方案之一——负载均衡

Tomcat集群session复制简介:将一台机器上的Session数据广播复制到集群中其余机器上使用场景:机器较少,网络流量较小优点:实现简单、配置较少、当网络中有机器Down掉时不影响用户访问缺点:广播式复制到其余机器有一定延时,带来一定网络开销

多个服务器之间同步session,这样可以保证每个服务器上都有全部的session信息,不过当服务器数量比较多的时候,同步是会有延迟甚至同步失败;

实现方式参考:Tomcat集群和Session复制说明

简介:将Session存入分布式缓存集群中的某台机器上,当用户访问不同节点时先从缓存中拿Session信息使用场景:集群中机器数多、网络环境复杂优点:可靠性好缺点:实现复杂、稳定性依赖于缓存的稳定性、Session信息放入缓存时要有合理的策略写入

把session放到Redis中存储,虽然架构上变得复杂,并且需要多访问一次Redis,但是这种方案带来的好处也是很大的:实现session共享,可以水平扩展(增加Redis服务器),应用服务器重启session不丢失(不过也要注意session在Redis中的刷新/失效机制),不仅可以跨服务器session共享,甚至可以跨平台(例如网页端和APP端)。

指定某一个节点执行通过特定IP限制,在定时任务的代码上加一段逻辑:仅某个ip的服务器能运行该定时任务。

优点:解决方法容易理解,部署简单,不需要多套代码。

缺点:

需要修改现有代码;

存在单点问题,只能规定一台服务器运行,发生故障时需要人工介入。

通过锁控制锁的性质需满足悲观、独占、非自旋、分布式。

在定时任务业务逻辑执行前先尝试获取锁,谁获取到谁执行,拿不到锁就直接放弃,或者进行其他的处理逻辑。

优点:解决单点问题

缺点:无法故障转移

利用quartz集群分布式(并发)部署解决方案

quartz自身提供了集群分布式(并发)部署的一套解决方案,主要解决思路是通过数据库锁的方式实现。

实现原理和解决方案和Quartz-cluster最佳实践特性:

1.持久化任务:当应用程序停止运行时,所有调度信息不被丢失,当你重新启动时,调度信息还存在,这就是持久化任务(保存到数据库表中)。

2.集群和分布式处理:当在集群环境下,当有配置Quartz的多个客户端时(节点),采用Quartz的集群和分布式处理时,我们要了解几点好处

2)Quartz调度是通过触发器的类别来识别不同的任务,在不同的节点定义相同的触发器的类别,这样在集群下能稳定的运行,一个节点无法完成的任务,会被集群中拥有相同的任务的节点取代执行。

有两点需要注意:

1)集群配置文件quartz.properties部署的时候必须要一致

2)集群建立起来之后,如果运行过程中需要修改quartz调度器的策略,例如:原来每5天执行一次任务,现在要改成每半个月执行一次,这个时候要修改所有的配置文件,并且要重新执行数据库脚本,或者手动修改数据库中存的corn表达式(容易改错),或找到那条记录删除(多表主外键关联)。

实现步骤:

1)修改quartz.properties配置文件

配置文件详解和quartz配置详解

org.quartz.jobStore.misfireThreshold=120000org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTXorg.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegateorg.quartz.jobStore.tablePrefix=QRTZ_org.quartz.jobStore.dataSource=myDSorg.quartz.jobStore.isClustered=trueorg.quartz.jobStore.acquireTriggersWithinLock=trueorg.quartz.jobStore.clusterCheckinInterval=15000org.quartz.jobStore.maxMisfiresToHandleAtATime=12)导入表结构,

quartz-2.3.0.jar!\org\quartz\impl\jdbcjobstore\tablesmysqlinnodb.sql

DROPTABLEIFEXISTSQRTZ_FIRED_TRIGGERS;DROPTABLEIFEXISTSQRTZ_PAUSED_TRIGGER_GRPS;DROPTABLEIFEXISTSQRTZ_SCHEDULER_STATE;DROPTABLEIFEXISTSQRTZ_LOCKS;DROPTABLEIFEXISTSQRTZ_SIMPLE_TRIGGERS;DROPTABLEIFEXISTSQRTZ_SIMPROP_TRIGGERS;DROPTABLEIFEXISTSQRTZ_CRON_TRIGGERS;DROPTABLEIFEXISTSQRTZ_BLOB_TRIGGERS;DROPTABLEIFEXISTSQRTZ_TRIGGERS;DROPTABLEIFEXISTSQRTZ_JOB_DETAILS;DROPTABLEIFEXISTSQRTZ_CALENDARS;......图片

优点:

1)框架自带功能,实现方式对外透明

2)不需要改代码,对现有业务影响较小。

第4.4章节中,使用jvm内存缓存了一些基础数据,当集群部署后,这些数据会在每个jvm都缓存一份,无法做到数据唯一性。

RedisRedis是完全开源的,遵守BSD协议,是一个高性能的key-value数据库。

Redis与其他key-value缓存产品有以下三个特点:

Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。

Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。

Redis支持数据的备份,即master-slave模式的数据备份。

Redis优势

性能极高–Redis能读的速度是110000次/s,写的速度是81000次/s。

丰富的数据类型–Redis支持二进制案例的Strings,Lists,Hashes,Sets及OrderedSets数据类型操作。

原子–Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。

丰富的特性–Redis还支持publish/subscribe,通知,key过期等等特性。

Redis与其他key-value存储有什么不同?

Redis有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其他数据库的进化路径。Redis的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。

Redis运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,因为数据量不能大于硬件内存。在内存数据库方面的另一个优点是,相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样Redis可以做很多内部复杂性很强的事情。同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。

Redis和Memcache区别,优缺点对比图片

1、Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等。2、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储。3、分布式–设定memcache集群,利用magent做一主多从;redis可以做一主多从。都可以一主一从4、存储数据安全–memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化)5、灾难恢复–memcache挂掉后,数据不可恢复;redis数据丢失后可以通过aof恢复6、Redis支持数据的备份,即master-slave模式的数据备份。

总结一下,有持久化需求或者对数据结构和处理有高级要求的应用,选择redis,其他简单的key/value存储,选择memcache。

用于控制定时任务由哪个节点执行,若4.5节中采用quartz自带功能解决,则不需引入分布式锁。

分布式锁三种实现方式:

1、基于数据库实现分布式锁;

2、基于缓存(Redis等)实现分布式锁;

3、基于Zookeeper实现分布式锁。

数据库实现分布式锁基于数据库实现的分布式锁,是最容易理解的。但是,因为数据库需要落到硬盘上,频繁读取数据库会导致IO开销大,因此这种分布式锁适用于并发量低,对性能要求低的场景。

基于数据库实现分布式锁比较简单,绝招在于创建一张锁表,为申请者在锁表里建立一条记录,记录建立成功则获得锁,消除记录则释放锁。

该方法依赖于数据库,优点就是容易理解,实现简单,但缺点也很明显:

1)单点故障问题。一旦数据库不可用,会导致整个系统崩溃。

Redis(缓存)实现分布式锁基于缓存实现分布式锁的方式,也就是说把数据存放在计算机内存中,不需要写入磁盘,减少了IO读写。

相对于基于数据库实现分布式锁的方案来说,基于缓存实现的分布式锁的优势表现在以下几个方面:

1)性能更好。数据被存放在内存,而不是磁盘,避免了频繁的IO操作。

2)很多缓存可以跨集群部署,避免了单点故障问题。

3)使用方便。很多缓存服务都提供了可以用来实现分布式锁的方法,比如Redis的setnx和delete方法等。

ZK分布式锁实现ZooKeeper基于树形数据存储结构实现分布式锁,来解决多个进程同时访问同一临界资源时,数据的一致性问题。ZooKeeper基于临时顺序节点实现了分布锁。

临时节点(EPHEMERAL):当客户端与Zookeeper连接时临时创建的节点。与持久节点不同,当客户端与ZooKeeper断开连接后,该进程创建的临时节点就会被删除。

可以解决前两种方法提到的各种问题,比如单点故障、不可重入、死锁等问题。但该方法实现较复杂,且需要频繁地添加和删除节点,所以性能不如基于缓存实现的分布式锁。

缺点:性能不如Redis分布式锁实现。

图片

这里的实现复杂性,是针对同样的分布式锁的实现复杂性,与之前提到的基于数据库的实现非常简易不一样。

总结来说,ZooKeeper分布式锁的可靠性最高,有封装好的框架,很容易实现分布式锁的功能,并且几乎解决了数据库锁和缓存式锁的不足,因此是实现分布式锁的首选方法。

技术选择

负载均衡:使用哪种负载均衡策略不需要我们关心,由运维支持,告知需负载均衡即可。(若公司需自己搞,推荐Nginx)

THE END
1.牵一发而动全身意思出处释义比喻动极小的部分就会影响全局。 出处清·龚自珍《自春徂秋偶有所感触》诗:“一发不可牵,牵之动全身。” 示例 人气14033次 相关百度“牵一发而动全身”谷歌“牵一发而动全身” 牵一发而动全身成语接龙:牵一发而动全身 →身临其境→ 找不到合适的成语...https://chengyu.t086.com/cy7/7569.html
2.牵一发而动全身意思成语解释牵一发而动全身: 发音:qiān yī fà ér dòng quán shēn 释义:比喻动极小的部分就会影响全局。 出处:清·龚自珍《自春徂秋偶有所感触》诗:“一发不可牵,牵之动全身。” 示例: 查字义:牵一发而动全身 复制网址 其他成语:谦谦君子气涌如山https://bajiu.cn/chengyu/?id=17894
3.牵一发而动全身的意思,用牵一发而动全身造句,典故,出处,成语接龙...牵一发而动全身 (qiān yī fà ér dòng quán shēn) 意思:比喻动极小的部分就会影响全局。 出处: 清·龚自珍《自春徂秋偶有所感触》诗:“一发不可牵,牵之动全身。” 造句: 成语接龙: 生不逢辰生不逢时深闭固拒深不可测身败名裂身不由己...http://www.zhujiangroad.com/tool/chengyu/daquan/%C7%A3%D2%BB%B7%A2%B6%F8%B6%AF%C8%AB%C9%ED.htm
4.动一发而牵全身牵一发而动全身牵一发而动全身什么意思牵一发而动全身出处,牵一发而动全身是什么意思,牵一发而动全身的读音,牵一发而动全身的意思解释,牵一发而动全身的近义词,牵一发而动全身的反义词,动一发而牵全身,牵一发而动全身,牵一发而动全身什么意思https://m.gushici.com/cy_46161
5.心猿意马,姆总牵一发动全身心猿意马,姆总牵一发动全身 惊不惊喜,意不意外?姆巴佩的问题还没搞定,内马尔又开始折腾了。本周一,包括《队报》《天空体育》在内的多家欧洲媒体同时披露,巴西人已经正式向巴黎圣日耳曼递交转会申请,希望能在今夏离队。 本版撰稿 特约记者 谢勤德 今夏有关内马尔的转会传闻不少,但之前都没有走到正式提交转会...http://paper.xinmin.cn/html/dfsports/2023-08-09/A08/47593.html
6.牵一发而动全身牵一发而动全身的意思成语用法复句式;作宾语、分句;比喻动极小的部分就会影响全局 例子熊召政《张居正》第二卷第五回:“虽有商榷之处,却也是牵一发而动全身的问题。” 英文翻译a slight more in one part may affect the situation as a whole 产生年代近代 常用程度常用...https://www.diyifanwen.com/chengyu/chengyu-q/234837873.htm
1.成語詞典/牽一髮而動全身補充資訊 參看站外新版《一把刀成語詞典》附帶真人國語讀音、成語接龍等功能,請查看該成語:牽一髮而動全身 單字解釋:牵、一、发、而、动、全、身(鏈接到《一把刀中文字典》) 關于“成語詞典/牽一髮而動全身”的用戶留言: 目前暫無留言 新增相關留言?...https://tw.m.18dao.net/%E6%88%90%E8%AA%9E%E8%A9%9E%E5%85%B8/%E7%89%BD%E4%B8%80%E9%AB%AE%E8%80%8C%E5%8B%95%E5%85%A8%E8%BA%AB
2.牵一发而动全身的意思和用法示例出处清 龚自珍《上大学士书》:“故事何足拘泥?但天下事,有牵一发而全身为之动者,不得不引申触类及之也。” 笔画顺序 用法示例 用法复句式;作宾语、分句;比喻动极小的部分就会影响全局。 感情牵一发而动全身是中性词,需注意。 近义牵一发动全身 ...https://chengyu.yr35.com/idiom/11654.html
3.牵一发而动全身的意思牵一发而动全身成语接龙解释: 牵:拉。比喻动极小的部分就会影响全局。 语法: 作宾语、分句;指动极小的部分就会大动。 典故出处: 清·龚自珍《上大学士书》:“故事何足拘泥?但天下事,有牵一发而全身为之动者,不得不引申触类及之也。" 成语示例:熊召政《张居正》第二卷第五回:“虽有商榷之处,却也是~的问题。" ...https://chengyu.xuenb.com/id-23392.html
4.动一发而牵全身还是牵一发而动全身,牵一发而动全身的牵是什么意思5、牵一发而动全身的成语解释 【繁体写法】:牵一发而动全身 【牵一发而动全身是什么意思】:比喻动...https://edu.iask.sina.com.cn/jy/31WEvw178d3.html
5.动一发而牵全身(关于动一发而牵全身的基本详情介绍)摘要:大家好我是小蝌蚪,动一发而牵全身,关于动一发而牵全身的基本详情介绍很多人还不知道,那么现在让我们一起来看看吧! 1、牵一发而动全身,汉语成语,拼音是qiānyīfàérdòngquánshēn。 2、比喻动极小的部分就会影响全局。 3、出自《自春徂秋偶有所感触》。 4、作宾语、分句;含褒义。 本文关于动一发而...https://baike.baijiantest.com/1687112666977533952
6.牵一发而动全身《文学遗产》1999年05期牵一发而动全身 吴战垒 开通知网号 《北宋文人和党争》,沈松勤著。286千字。人民出版社1998年12月版。责任编辑:张秀平北宋党争肇端于仁宗景钻、庆历年间,盛行于神宗熙宁以后,而迄于北宋灭亡,长达半个多世纪。它围绕政治革新的不同政见之争,而牵动了朝政兴革、朝臣进败,并波及文化学术、诗文创作等不同层 (共...https://mall.cnki.net/magazine/Article/WXYC199905017.htm
7.牵一发而动全身(教师中心稿)因此,千百年来,庖丁成了经验者的化身,庖丁解牛则成了人们寻找规律的依据。有人找到了熟能生巧的做事之道,有人找到了遵循规律的成功之道,也有人找到了顺应自然的养生之道。而笔者找到的是整体把握文章内容的学习之道──牵一发而动全身。 牛有牛的结构,文章也有文章的结构,从某种意义上说,析出文章的结构比解...https://teacher.ruiwen.com/news/24563.htm
8.一举一动都产生着重大的影响的四字成语是什么4、动一发而牵全身的成语 5、深受影响的四字成语有哪些? 是什么成语的意思是所处地位重要,一举一动都关系到全局 举足轻重 [jǔ zú qīng zhòng ]生词本 基本释义 详细释义 [jǔ zú qīng zhòng ]只要脚移动一下,就会影响两边的轻重。指处于重要地位,一举一动都足以影响全局。 https://www.oilube.cn/91698.html
9.牵一发动全身汽车制动原理解释制动的整个过程涉及到比较多的能量转换,可谓是牵一发动全身。当驾驶者踩下刹车踏板,制动踏板向下的行程中会推动制动总泵工作,总泵中的制动液会被输送到各个分泵中,在盘式制动中,分泵也就是刹车卡钳中的活塞,当活塞被推动后,会与刹车碟产生强烈的摩擦力,继而产生一股制动力,使汽车减速或者停下。制动力与制动性能...https://www.dongchedi.com/article/6752731476141277709
10.《河神2》为何不再引人入胜?难道只是因为换了男主吗?(河神)剧评氛围营造的相当成功,是《河神》系列用心潜制的结果,这一点堪称业界良心。说是楷模,也不为过。因此,基于这点,还是推荐大家去看一看的。河神2剧照唯一男主更换,是弊也是利每部系列作品,在开篇获得市场好评后,都会争取做出下一部作品,这是对市场、片方等多方面都利好的事情。而在后续项目的开发过程中,观众最为...https://movie.douban.com/review/14469041/
11.新疆历史上分裂与反分裂战争,喀什为什么是关键点?牵一发足以动全身综上时跨近两千年中在新疆发生的分裂与反分裂较量的著名事件,我们可以看出,尽管其形式不同,然其成也喀什、其败也喀什的特点却惊人地相似。曾问吾在《中国经营西域史》一书中道破天机: 我国无帕米尔,则无疏勒(今喀什);无疏勒,则无新疆;牵一发足以动全身,足见其地关系边防之重大。http://www.wyzxwk.com/e/mp/content.php?classid=18&id=442037
12.文汇报②丨种好“立法试验田”,让改革更具穿透力坚持问题导向,找准“牵一发动全身”关键点 深化立法领域改革,意味着将有限的立法资源用在刀刃上。 “切口小、聚焦解决现实问题,这是数十年地方立法的成功经验,也符合全国人大对地方立法的要求。”在沈国明看来,地方立法不应追求体系化,也不能满足于将相关政策法条化,而应当注重可操作性。 https://www.jfdaily.com/sgh/detail?id=1425720