330

ASP.NET Core 1.0 High Performance

Embed Size (px)

Citation preview

Page 1: ASP.NET Core 1.0 High Performance
Page 2: ASP.NET Core 1.0 High Performance

ASP.NETCore1.0HighPerformance

Page 3: ASP.NET Core 1.0 High Performance

TableofContents

ASP.NETCore1.0HighPerformanceCreditsForewordAbouttheAuthorAcknowledgmentsAbouttheReviewerwww.PacktPub.com

eBooks,discountoffers,andmoreWhysubscribe?

PrefaceWhatthisbookcoversWhatyouneedforthisbookWhothisbookisforConventionsReaderfeedbackCustomersupport

DownloadingtheexamplecodeErrataPiracyQuestions

1.WhyPerformanceIsaFeaturePerformanceasafeatureCommonclassesofperformanceproblems

LanguageconsiderationsTypesofperformanceproblems

WhenperformancemattersSlowerissometimesbetter

WhyissuesaremissedMeasuring

ThebenefitsofplanningaheadUnderstandinghardware

StorageaccessspeedsScalingapproachchanges

ToolsandcostsToolsLookingatsomealternativetools

Thenew.NETSummary

2.MeasuringPerformanceBottlenecksTools

SQL

Page 4: ASP.NET Core 1.0 High Performance

SQLServerProfilerExecutingasimplequery

MiniProfilerApplicationprofiling

GlimpseUsingGlimpse

IDEMonitoringHTTP

BrowsersChromeFirefox

FiddlerNetwork

MicrosoftMessageAnalyzerWireshark

RollyourownScience

RepeatabilityOnlychangeonething

Summary3.FixingCommonPerformanceProblems

LatencyAsynchronousoperations

SimpleasynchronoustoolsBackgroundqueuingHangfire

SelectN+1problemsEfficientpagingStaticsitegenerators

PragmaticsolutionswithhardwareAdesktopexampleWebapplications

OversizedimagesImageresolutionImageformat

Summary4.AddressingNetworkPerformance

InternetprotocolsTCP/IP

Slow-startHTTP

HeadersHTTPmethodsStatuscodes

Page 5: ASP.NET Core 1.0 High Performance

EncryptionKeyexchangeDelaydiagnosticsPerformancetweaks

HTTP/2WebSockets

CompressionLosslesscompressionalgorithmsBundlingandminification

BundlingMinificationChangesinASP.NETCore

ImageoptimizationPNGJPEGOtherimageformatsResizingimages

CachingBrowserServerProxyserversbetweenyouandyourusers

CDNsSummary

5.OptimizingI/OPerformanceInput/output

CategoriesofI/ODisksVirtualfilesystemsDatabasesAPIs

NetworkdiagnosticstoolsPingTracertNslookupBuildyourown

SolutionsBatchingAPIrequestsEfficientDBoperations

DatabasetuningReporting

AggregatesSampling

InsertingdataGUIDs

Page 6: ASP.NET Core 1.0 High Performance

AdvancedDBtopicsSimulationandtestingSummary

6.UnderstandingCodeExecutionandAsynchronousOperationsGettingstartedwiththecoreprojects

.NETCoreASP.NETCore

KestrelDatastructures

ListsDictionariesCollectionbenchmarksBloomfilters

HashingandchecksumsHashingbenchmarks

SerializationSIMDCPUinstructionsParallelprogramming

TaskParallelLibraryParallelLINQParallelbenchmarkingParallelprogramminglimitations

PracticestoavoidReflectionRegularexpressionsStringconcatenationintightloopsDynamictypingSynchronousoperationsExceptions

Summary7.LearningCachingandMessageQueuing

WhycachingishardWebcaching

CachingbackgroundHTTPheadersCachebusting

ServiceworkersServiceworkerexample

WebandproxyserversIISVarnish

WorkingwithacontentdeliverynetworkWhennottocache

Applicationlayercaching

Page 7: ASP.NET Core 1.0 High Performance

RedisDatabaseresultsetcaching

MessagequeuingCoffeeshopanalogyMessagequeuingstylesCommonmessagingpatterns

UnicastPub/sub

RabbitMQQueuingframeworksandlibraries

Summary8.TheDownsidesofPerformance-EnhancingTools

ManagingcomplexityUnderstandingcomplexityComplexityreduction

FrameworksArchitecture

MonolithversusmicroservicesArchitecturecomparison

RefactoringAcultureofhighperformance

AblamelesscultureIntellectualdishonestySlowdowntogofasterFromthegroundupSharedvalues

ThepriceofperformanceDistributeddebugging

LoggingErrorloggingApplicationInsightsIntegratedloggingCentralizedlogging

StatisticsManagingstalecachesSummary

9.MonitoringPerformanceRegressionsProfilingandmeasurementTesting

AutomatedtestingContinuousintegrationSlowtestingFixingperformanceregressionsLoadtesting

Page 8: ASP.NET Core 1.0 High Performance

RealismRealisticenvironmentsRealisticworkloads

FeatureswitchingExperimentingforscienceA/BtestingUserinterfacetesting

WebUItestingtoolsAutomatingUIperformancetests

StayingalertDevOps

DevOpstoolingProvisioningMonitoring

HostingSummary

10.TheWayAheadReviewingwhatwelearnedFurtherreading

GoingnativeProcessorarchitectureHardwareishardMachinelearningBigdataandMapReduceOrleansCustomtransportsAdvancedhashing

LibraryandframeworksupportThefutureSummary

Page 9: ASP.NET Core 1.0 High Performance

ASP.NETCore1.0HighPerformance

Page 10: ASP.NET Core 1.0 High Performance

ASP.NETCore1.0HighPerformanceCopyright©2016PacktPublishing

Allrightsreserved.Nopartofthisbookmaybereproduced,storedinaretrievalsystem,ortransmittedinanyformorbyanymeans,withoutthepriorwrittenpermissionofthepublisher,exceptinthecaseofbriefquotationsembeddedincriticalarticlesorreviews.

Everyefforthasbeenmadeinthepreparationofthisbooktoensuretheaccuracyoftheinformationpresented.However,theinformationcontainedinthisbookissoldwithoutwarranty,eitherexpressorimplied.Neithertheauthor,norPacktPublishing,anditsdealersanddistributorswillbeheldliableforanydamagescausedorallegedtobecauseddirectlyorindirectlybythisbook.

PacktPublishinghasendeavoredtoprovidetrademarkinformationaboutallofthecompaniesandproductsmentionedinthisbookbytheappropriateuseofcapitals.However,PacktPublishingcannotguaranteetheaccuracyofthisinformation.

Firstpublished:June2016

Productionreference:1170616

PublishedbyPacktPublishingLtd.

LiveryPlace

35LiveryStreet

Birmingham

B32PB,UK.

ISBN978-1-78588-189-3

www.packtpub.com

Page 11: ASP.NET Core 1.0 High Performance

Credits

Author

JamesSingleton

CopyEditor

PriyankaRavi

Reviewer

JasonDeOliveira

ProjectCoordinator

SuzanneCoutinho

CommissioningEditor

EdwardGordon

Proofreader

SafisEditing

AcquisitionEditor

ChaitanyaNair

Indexer

MariammalChettiyar

ContentDevelopmentEditor

MerintThomasMathew

Graphics

KirkD'Penha

TechnicalEditor

KunalChaudhari

ProductionCoordinator

MelwynDsa

Page 12: ASP.NET Core 1.0 High Performance

Foreword

"Themostamazingachievementofthecomputersoftwareindustryisitscontinuingcancellationofthesteadyandstaggeringgainsmadebythecomputerhardwareindustry."

--HenryPetroski

Weliveintheageofdistributedsystems.Computershaveshrunkfromroom-sizedindustrialmainframestoembeddeddevicesthataresmallerthanathumbnail.However,atthesametime,thesoftwareapplicationsthatwebuild,maintain,anduseeverydayhavegrownbeyondmeasure.Wecreatedistributedapplicationsthatrunonclustersofvirtualmachinesscatteredallovertheworld,andbillionsofpeoplerelyonthesesystems,suchase-mail,chat,socialnetworks,productivityapplications,andbanking,everyday.We'reonline24hoursaday,sevendaysaweek,andwe'rehookedoninstantgratification.Agenerationago,we'dhappilywaituntilaftertheweekendforachequetoclear,orallow28daysfordelivery.Today,weexpectinstantfeedback,andwhyshouldn'twe?Themodernwebisreal-time,immediate,on-demand,builtonpacketsofdataflashingaroundtheworldatthespeedoflight,andwhenitisn't,wenotice.We'veallhadthatsinkingfeeling...youknow,whenyou'vejustputyourcreditcardnumberintoapagetobuysomeexpensiveconcerttickets,andthesitetakesjustalittletoolongtorespond.Performanceandresponsivenessareafundamentalpartofdeliveringgreatuserexperienceinthedistributedage.However,foraworkingdevelopertryingtoshipyournextfeatureontime,performanceisoftenoneofthemostchallengingrequirements.Howdoyoufindthebottlenecksinyourapplicationperformance?Howdoyoumeasuretheimpactofthoseproblems?Howdoyouanalyzethem,designandtestsolutionsandworkarounds,andmonitortheminproductionsothatyoucanbeconfidentthattheywon'thappenagain?

Thisbookhastheanswers.Inside,JamesSingletonpresentsapragmatic,in-depth,andbalanceddiscussionofmodernperformanceoptimizationtechniques,andhowtoapplythemtoyour.NETandwebapplications.Startingfromthepremisethatweshouldtreatperformanceasacorefeatureofoursystems,JamesshowshowyoucanuseprofilingtoolssuchasGlimpse,MiniProfiler,Fiddler,andWiresharktotrackdownthebottlenecksandbugsthatcauseyourperformanceproblems.Headdressesthescientificprinciplesbehindeffectiveperformancetuning,monitoring,instrumentation,andtheimportanceofusingaccurateandrepeatablemeasurementswhenyoumakechangestoarunningsystemtotryandimproveperformance.

Thisbookgoesontodiscussalmosteveryaspectofmodernapplicationdevelopment:databasetuning,hardwareoptimisations,compressionalgorithms,networkprotocols,andobject-relationalmappers.Foreachtopic,Jamesdescribesthesymptomsofcommonperformanceproblems,identifiestheunderlyingcausesofthosesymptoms,andthendescribesthepatternsandtoolsthatyoucanusetomeasureandfixtheseunderlyingcausesinyourownapplications.There'sin-depthdiscussionofhigh-performancesoftwarepatternssuchasasynchronousmethodsandmessagequeues,accompaniedbyreal-worldexamplesshowingyouhowtoimplementthesepatternsinthelatestversionsofthe.NETframework.Finally,Jamesshowshowyoucannotonlyloadtestyour

Page 13: ASP.NET Core 1.0 High Performance

applicationsasapartofyourreleasepipeline,butyoucancontinuouslymonitorandmeasureyoursystemsinproduction,lettingyoufindandfixpotentialproblemslongbeforetheystartupsettingyourendusers.

WhenIworkedwithJameshereatSpotlight,heconsistentlydemonstratedaremarkablebreadthofknowledge,fromASP.NETtoArduinos,fromResharpertoresistors.Oneday,he'dbuildreactivefrontendinterfacesinASP.NETandJavaScript,thenexthe'dcreatebuildmonitorsbywiringmicrocontrollersintoStarWarstoys,orworkingouthowtoconnectthebathroomdoorlocktotheintranetsothatourbicyclingemployeescouldseefromtheirdeskswhentheofficeshowerwasfree.AfterJamesmovedonfromSpotlight,I'vebeenfollowinghisworkwithCleanwebandComputing4KidsEducation.He'soneofthoseraredeveloperswhoreallyunderstandsthesocialandenvironmentalimplicationsoftechnology—thatwhetherit'sdeliveringgreatuserinteractionsorjustsavingelectricity,improvingyoursystems'performanceisagreatwaytodelightyourusers.Withthisbook,Jameshasdistilledyearsofhands-onlessonsandexperienceintoatrulyexcellentall-roundreferencefor.NETdeveloperswhowanttounderstandhowtobuildresponsiveandscalableapplications.It'sagreatresourcefornewdeveloperswhowanttodevelopaholisticunderstandingofapplicationperformance,butthecoverageofcutting-edgetechniquesandpatternsmeansit'salsoidealformoreexperienceddeveloperswhowanttomakesurethey'renotgettingleftbehind.Buyit,readit,shareitwithyourteam,andlet'smakethewebabetterplace.

DylanBeattie

Systemsarchitect

RESTevangelist,technicalspeaker

Co-organizeroftheLondon.NETUserGroup

Page 14: ASP.NET Core 1.0 High Performance

AbouttheAuthorJamesSingletonisaBritishsoftwaredeveloper,engineer,andentrepreneur,whohasbeenwritingcodesincethedaysoftheBBCMicro.Hisformaltrainingisinelectricalandelectronicengineering,yethehasworkedprofessionallyin.NETsoftwaredevelopmentfornearlyadecade.

HeisactiveintheLondonstart-upcommunityandhelpsorganizeCleanwebLondoneventsforenvironmentallyconscioustechnologists.HerunsCleanwebJobs,whichaimstohelpgetdevelopers,engineers,managers,anddatascientistsintorolesthatcanhelptackleclimatechangeandotherenvironmentalproblems.Healsodoespublicspeaking,andhehaspresentedtalksatmanylocalusergroups,includingattheHackerNewsLondonmeetup.

Jamesholdsafirstclassdegree(withhonors)inelectronicengineeringwithcomputing,andhehasdesignedandbuilthisownbasicmicroprocessoronanFPGAalongwithacustominstructionsettorunonit.HeisalsoaScience,Technology,Engineering,andMathematics(STEM)ambassador,whoencouragesyoungpeopletostudythesefields.

Jamescontributestoandisinfluencedbymanyopensourceprojects,andregularlyusesalternativetechnologies,suchasPython,Ruby,andLinux.HeisenthusiasticaboutthedirectionthatMicrosoftistaking.NETinandtheirembracingofopensourcepractices.

Heisparticularlyinterestedinhardware,environmental,anddigitalrightsprojectsandiskeenonsecurity,compression,andalgorithms.Whennothackingoncode,orwritingforbooksandmagazines,heenjoyswalking,skiing,rockclimbing,traveling,brewing,andcraftbeer.

Jameshasgainedvariedskillsfromworkinginmanydiverseindustriesandroles,fromhighperformancestockexchangestovideoencodingsystems.Hehasworkedasabusinessanalyst,consultant,tester,developer,andtechnicalarchitect.Hehasawiderangeofknowledge,gainedfrombigcorporatestostartups,andalotofplacesinbetween.Hehasfirst-handexperienceofthebestandworstwaysofbuildinghighperformancesoftware.

Youcanreadhisblogatunop.uk.

Page 15: ASP.NET Core 1.0 High Performance

AcknowledgmentsIwouldliketothankallofmyfriendsandfamilyforbeingsosupportivewhileI'vebeenworkingonthisbook.Iwouldespeciallyliketothankmydadforgettingmeintotechnologyatayoungage,andLouforherlimitlessenthusiasmandpositivity.IwouldalsoliketothankDylanforwritingtheforewordtothisbook.

Writingabookismuchharderworkthanmostpeopleprobablyimagine,andIcouldn'thavedoneitwithouttheconstantencouragement.ManysacrificesneededtobemadeandIthankeveryonefortheirunderstanding.SorryforalltheeventsthatI'vehadtomissandtoanyonewhoI'veforgottentothankhere.

IwouldalsoliketoacknowledgeRadioParadiseforkeepingmesanefromthenoiseoftheinconsiderateconstructorsnextdoor.Finally,IapologizeinadvancetomyBritish(orAussie,Kiwi,Canadian,andsoon)readersforanyoftheless-correctlyspelledwordsusedinthisbook.

Page 16: ASP.NET Core 1.0 High Performance

AbouttheReviewerJasonDeOliveiraworksasCTOforMEGAInternational(http://www.mega.com),aSoftwareCompanyinParis(France)thatprovidesModelingToolsforEnterpriseArchitecture,EnterpriseGovernanceRisk,andComplianceManagement.HeisanexperiencedManagerandSeniorSolutionsArchitectwithhighskillsinSoftwareArchitectureandEnterpriseArchitecture.

Helovessharinghisknowledgeandexperienceviahisblog,byspeakingatconferences,writingtechnicalbooks,writingarticlesinthetechnicalpress,givingsoftwarecoursesasMCT,andcoachingco-workersinhiscompany.HefrequentlycollaborateswithMicrosoft,andyoucanfindhimquiteoftenattheMicrosoftTechnologyCenter(MTC)inParis.

Microsoftawardedhimin2011withtheMicrosoft®MostValuableProfessional(MVPC#)AwardforhisnumerouscontributionstotheMicrosoftcommunity.MicrosoftseekstorecognizethebestandbrightestfromtechnologycommunitiesaroundtheworldwiththeMVPAward.Theseexceptionalandhighly-respectedindividualscomefrommorethan90countries,servetheirlocalonlineandofflinecommunities,andhaveanimpactworldwide.Jasonisveryproudtobeoneofthem.

Pleasefeelfreetocontacthimviahisblogifyouneedanytechnicalassistanceorwanttodiscusstechnicalsubjects(http://www.jasondeoliveira.com).

Jasonhasworkedonthefollowingbooks:

.NET4.5ExpertProgrammingCookbook(English)WCF4.5Multi-tierServicesDevelopmentwithLINQtoEntities(English).NET4.5ParallelExtensionsCookbook(English)WCF4.5Multi-layerServicesDevelopmentwithEntityFrameworkThirdEdition(English)VisualStudio2013:Concevoir,développeretgérerdesprojetsWeb,lesgéreravecTFS2013(French)

Iwouldliketothankmylovelywife,Orianne,andmybeautifuldaughters,JuliaandLéonie,forsupportingmeinmyworkandforacceptinglongdaysandshortnightsduringtheweekandsometimesevenduringtheweekend.Mylifewouldnotbethesamewithoutthem!

Page 17: ASP.NET Core 1.0 High Performance

www.PacktPub.com

Page 18: ASP.NET Core 1.0 High Performance

eBooks,discountoffers,andmoreDidyouknowthatPacktofferseBookversionsofeverybookpublished,withPDFandePubfilesavailable?YoucanupgradetotheeBookversionatwww.PacktPub.comandasaprintbookcustomer,youareentitledtoadiscountontheeBookcopy.Getintouchwithusatcustomercare@packtpub.comformoredetails.

Atwww.PacktPub.com,youcanalsoreadacollectionoffreetechnicalarticles,signupforarangeoffreenewslettersandreceiveexclusivediscountsandoffersonPacktbooksandeBooks.

https://www2.packtpub.com/books/subscription/packtlib

DoyouneedinstantsolutionstoyourITquestions?PacktLibisPackt'sonlinedigitalbooklibrary.Here,youcansearch,access,andreadPackt'sentirelibraryofbooks.

Page 19: ASP.NET Core 1.0 High Performance

Whysubscribe?FullysearchableacrosseverybookpublishedbyPacktCopyandpaste,print,andbookmarkcontentOndemandandaccessibleviaawebbrowser

Page 20: ASP.NET Core 1.0 High Performance

PrefaceMicrosofthasreleasedanewopensourceandcross-platformwebapplicationframework,calledASP.NETCore.Itrunsontopof.NETCore,whichisalsoopensource,andisprimarilyusedwiththeC#programminglanguage.YouarenolongertiedtousingWindowswithASP.NET,andyoucannowdeveloponaMacanddeploytoLinux.Thisnewplatformalsooffersmuchhigherperformance.

Intoday'sworld,awebapplicationthatonlyperformswellonadeveloper'sworkstationandfailstodeliverhigh-performanceinproduction,isunacceptable.Thewaythatwebapplicationsarenowdeployedatscalehaschanged,anddevelopmentpracticesmustadapttotakeadvantageofthis.Byreadingthisbook,you'lllearnaboutthemodernwayofmakinghigh-performancewebapplications,andhowtodothiswithASP.NETCore.

Thisbookaddresseswebapplicationperformance-improvementtechniquesfrombothageneralstandpoint(HTTP,HTTPS,HTTP/2,TCP/IP,databaseaccess,compression,I/O,assetoptimization,caching,messagequeuing,andotherconcerns)andfromaC#,ASP.NETCore,and.NETCoreperspective.Thisincludesdelvingintothedetailsofthelatestframeworksanddemonstratingsoftwaredesignpatternsthatimproveperformance.

Wewillhighlightcommonperformancepitfalls,whichcanoftenoccurunnoticedondeveloperworkstations,alongwithstrategiestodetectandresolvetheseissuesearly.Byunderstandingandaddressingchallengesupfront,youcanavoidnastysurpriseswhenitcomestodeploymenttime.

Wewillintroduceperformanceimprovementsalongwiththetrade-offsthattheyentail.Wewillstrikeabalancebetweenprematureoptimizationandinefficientcodebytakingascientificandevidence-basedapproach,focusingonthebigproblemsandavoidingchangesthathavelittleimpact.

Weassumethatyouunderstandtheimportanceofperformanceforwebapplications,butwewillrecapwhyit'scrucial.However,youmaynothavehadanyspecificoractionableadvice,orhavemuchexperienceofperformanceproblemsoccurringinthewild.

Byreadingthisbook,you'llunderstandwhatproblemscanoccurwhenwebapplicationsaredeployedatscaletodistributedinfrastructure,andknowhowtoavoidormitigatetheseissues.Youwillgainexperienceofhowtowritehigh-performanceapplicationswithouthavingtolearnaboutissuesthehardway,possiblylateatnight.

You'llseewhat'snewinASP.NETCore,whyit'sbeenrebuiltfromthegroundup,andwhatthismeansforperformance.Youwillunderstandthefutureof.NETCoreandhowyoucannowdeveloponanddeploytoWindows,MacOSX,andLinux.You'llappreciatetheperformanceofnewfeaturesinASP.NETCore,includingupdatestotheRazorviewengine,andyouwillbeawareofcrossplatformtools,suchasVisualStudioCode.

Page 21: ASP.NET Core 1.0 High Performance

WhatthisbookcoversLet'stakealookatwhattopicswe'llbecoveringthroughoutthebook.

Chapter1,WhyPerformanceIsaFeature,discussesthebasicpremiseofthisbookandshowsyouwhyyouneedtocareabouttheperformanceofyoursoftware.Responsiveapplicationsarevital,andit'snotsimplyenoughtohavefunctionalitywork,italsoneedstobequick.

Thinkofthelasttimeyouheardsomeonecomplainingaboutanapporwebsite,andit'slikelytheywereunhappywiththeperformance.Poorperformancedoesn'tonlymakeusersunhappy,italsoaffectsyourbottom-line.There'sgooddatatosuggestthatfastperformanceincreasesengagementandimprovesconversionrates,whichiswhyit'srewardedbysearchengines.

Chapter2,MeasuringPerformanceBottlenecks,tellsyouthattheonlywayyoucansolveperformanceproblemsistocarefullymeasureyourapplication.Withoutknowingwhereaproblemlies,yourchanceofsolvingitisextremelyslim,andyouwon'tevenknowwhetheryou'veimprovedmattersormadethingsworse.

Wewillhighlightafewwaysofmanuallymonitoringperformanceandsomehelpfultoolsthatyoucanusetomeasurestatistics.You'llseehowtogaininsightsintothedatabase,application,HTTP,andnetworklevelsofyoursoftwaresothatyouknowwhatisgoingoninternally.We'llalsoshowyouhowtobuildyourownbasictimingcodeandcovertheimportanceoftakingascientificapproachtotheresults.

Chapter3,FixingCommonPerformanceProblems,looksatsomeofthemostfrequentperformancemistakes.We'llshowyouhowtofixsimpleissuesacrossarangeofdifferentapplicationareas,forexample,howtooptimizemediawithimageresizingorencoding,SelectN+1problems,andasynchronousbackgroundoperations.

Wewillalsotalkalittleaboutusinghardwaretoimproveperformanceonceyouknowwherethebottleneckslie.Thisapproachbuysyousometimeandallowsyoutofixthingsproperlyatareasonablepace.

Chapter4,AddressingNetworkPerformance,digsintothenetworkinglayerthatunderpinsallwebapplications.We'llshowyouhowremoteresourcescanslowdownyourappanddemonstratewhatyoucandoaboutmeasuringandaddressingtheseproblems.

Wewilllookatinternetprotocols,includingTCP/IP,HTTP,HTTP/2,andWebSockets,alongwithaprimeronencryptionandhowallofthesecanalterperformance.We'llcovercompressionoftextualandimage-basedassets,includingsomeexoticimageformats.Finally,wewillintroducecachingatthebrowser,server,proxy,andContentDeliveryNetwork(CDN)levels,showingyousomeofthebasics.

Chapter5,OptimizingI/OPerformance,focusesoninput/outputandhowthiscannegatively

Page 22: ASP.NET Core 1.0 High Performance

affectperformance.Wewilllookatdisks,databases,andremoteAPIs,manyofwhichusethenetwork,particularlyifvirtualized.We'llcoverbatchingyourrequestsandoptimizingdatabaseusagewithaggregatesorsampling,aimingtoreducethedataandtimerequired.

Duetonetworking'subiquityincloudenvironments,we'llspendconsiderabletimeonnetworkdiagnostics,includingpinging,routetracing,andlookinguprecordsinthedomainnamesystem.You'lllearnhowlatencycanbedrivenbyphysicaldistance,orgeography,andhowthiscancauseproblemsforyourapplication.We'llalsodemonstratehowtobuildyourownnetworkinginformationgatheringtoolsusing.NET.

Chapter6,UnderstandingCodeExecutionandAsynchronousOperations,jumpsintotheintricaciesofC#codeandlooksathowitsexecutioncanalterperformance.We'lllookatthevariousopensourceprojectsthatmakeupASP.NETCoreand.NETCore,includingKestrel—ahigh-performancewebserver.

Wewillexaminetheimportanceofchoosingthecorrectdatastructuresandlookatvariousexamplesofdifferentoptions,suchaslistsanddictionaries.We'llalsolookathashing,serialization,andperformsomesimplebenchmarking.

Youwilllearnsometechniquesthatcanspeedupyourprocessingbyparallelizingit,suchasSingleInstructionMultipleData(SIMD)andparallelextensionsprogrammingwiththeTaskParallelLibrary(TPL)andParallelLINQ(PLINQ).You'llalsoseesomepracticesthatarebestavoided,duetotheirperformancepenalties,suchasreflectionandregularexpressions.

Chapter7,LearningCachingandMessageQueuing,initiallylooksatcaching,whichiswidelyregardedasdifficult.You'llseehowcachingworksfromaHTTPperspectiveinbrowsers,webservers,proxies,andCDNs.Youwilllearnaboutcachebusting(orbreaking)toforceyourchangesandusingthenewJavaScriptserviceworkersinmodernbrowserstogainfinercontrolovercaching.

Additionally,we'llexaminecachingattheapplicationanddatabaselevelsinyourinfrastructure.Wewillseethebenefitsofin-memorycaches,suchasRedis,andhowthesecanreducetheloadonyourdatabase,lowerlatency,andincreasetheperformanceofyourapplication.

Wewillinvestigatemessagequeuingasawaytobuildadistributedandreliablesystem.We'lluseanalogiestoexplainhowasynchronousmessagepassingsystemsworkandshowyousomecommonstylesofmessagequeuing,includingunicastandpub/sub.

Wewillalsoshowyouhowmessagequeuingcanbeusefultoaninternalcachinglayerbybroadcastingcacheinvalidationdata.You'lllearnaboutmessagebrokers,suchasRabbitMQ,andvariouslibrariestointeractwiththemfrom.NET.

Chapter8,TheDownsidesofPerformance-EnhancingTools,concentratesonthenegativesofthetechniquesthatwewillhavecoveredbecausenothingcomesforfree.We'lldiscussthevirtuesofvariousmethodstoreducecomplexity,useframeworks,anddesigndistributedarchitecture.We

Page 23: ASP.NET Core 1.0 High Performance

willalsocoverprojectcultureandseehowhigh-performanceisnotsimplyaboutcodebutaboutpeopletoo.

We'lllookintopossiblesolutionstotackletheproblemofdistributeddebuggingandseesomeavailabletechnologiestocentrallymanageapplicationlogging.We'llhaveabriefintroductiontostatisticssothatyoucanmakesenseofyourperformancemetrics,andwewilltouchuponmanagingcaches.

Chapter9,MonitoringPerformanceRegressions,againtakesalookatatmeasuringperformance,butinthiscase,fromanautomationandContinuousIntegration(CI)perspective.We'llreiteratetheimportanceofmonitoringandshowhowyoucanbuildthisintoyourdevelopmentworkflowtomakeitroutineandalmosttransparent.Youwillseehowitispossibletoautomatealmostanytypeoftesting,fromsimpleunittestingtointegrationtesting,andevencomplexbrowserUserInterface(UI)testing.

We'llshowyouhowyoucanmakeyourtestsmorerealisticandusefulusingtechniques,suchasblue-greendeploymentandfeatureswitching.YouwilldiscoverhowtoperformA/Btestingoftwoversionsofawebpagewithsomeverybasicfeatureswitchingandafewoptionsforfunhardwaretokeeppeopleengagedintestresults.We'llalsocoverDevOpspracticesandcloudhosting,bothofwhichmakeCIeasiertoimplementandcomplementitnicely.

Chapter10,TheWayAhead,brieflysumsupthelessonsofthebookandthenhasalookatsomeadvancedtopicsthatyoumayliketoreadmoreabout.Wewillalsotrytopredictthefutureforthe.NETCoreplatformsandgiveyousomeideastotakefurther.

Page 24: ASP.NET Core 1.0 High Performance

WhatyouneedforthisbookYouwillneedadevelopmentenvironmenttofollowthecodeexamplesinthisbook,eitherVisualStudioCommunity2015orVisualStudioCodeifyou'renotonWindows.Youcanalsouseyourtexteditorofchoiceandthedotnetcommandlinetool.IfyouuseVisualStudio,thenyoushouldalsoinstallthe.NETCoreSDKandtoolingandthelatestNuGetextension.

Forsomeofthechapters,youwillalsoneedSQLServer2014Express.Youcanuse2016too,particularlyifyouareonLinux.However,youcanalsouseAzureandrunagainstaclouddatabase.

Thereareothertoolsthatwewillcover,butwewillintroducetheseastheyareused.Thedetailedsoftware/hardwarelistisuploadedalongwiththecodefiles.

Page 25: ASP.NET Core 1.0 High Performance

WhothisbookisforThisbookismainlyaimedatASP.NETandC#developers,butdevelopersusedtootheropensourceplatformsmayalsobeinterestedin.NETCore.YoushouldhaveexperiencewiththeMVCframeworkforweb-applicationdevelopmentandbelookingtodeployapplicationsthatwillperformwellonlive-productionenvironments.Thesecanbevirtualmachinesorhostedbyacloud-serviceprovider,suchasAWSorAzure.

Page 26: ASP.NET Core 1.0 High Performance

ConventionsInthisbook,youwillfindanumberoftextstylesthatdistinguishbetweendifferentkindsofinformation.Herearesomeexamplesofthesestylesandanexplanationoftheirmeaning.

Codewordsintext,databasetablenames,foldernames,filenames,fileextensions,pathnames,dummyURLs,userinput,andTwitterhandlesareshownasfollows:"ThefetchfunctionisthemodernversionofanXMLHttpRequest."

Ablockofcodeissetasfollows:

varclient=newSmtpClient();

HostingEnvironment.QueueBackgroundWorkItem(ct=>

client.SendMailAsync(message));

Anycommand-lineinputoroutputiswrittenasfollows:

tracertec2.ap-southeast-2.amazonaws.com

Newtermsandimportantwordsareshowninbold.Wordsthatyouseeonthescreen,forexample,inmenusordialogboxes,appearinthetextlikethis:"IfyouselectCacheStorage,youwillseethecontentsofthecache."

Note

Warningsorimportantnotesappearinaboxlikethis.

Tip

Tipsandtricksappearlikethis.

Page 27: ASP.NET Core 1.0 High Performance

ReaderfeedbackFeedbackfromourreadersisalwayswelcome.Letusknowwhatyouthinkaboutthisbook-whatyoulikedordisliked.Readerfeedbackisimportantforusasithelpsusdeveloptitlesthatyouwillreallygetthemostoutof.Tosendusgeneralfeedback,[email protected],andmentionthebook'stitleinthesubjectofyourmessage.Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingorcontributingtoabook,seeourauthorguideatwww.packtpub.com/authors.

Page 28: ASP.NET Core 1.0 High Performance

CustomersupportNowthatyouaretheproudownerofaPacktbook,wehaveanumberofthingstohelpyoutogetthemostfromyourpurchase.

Page 29: ASP.NET Core 1.0 High Performance

DownloadingtheexamplecodeYoucandownloadtheexamplecodefilesforthisbookfromyouraccountathttp://www.packtpub.com.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.

Youcandownloadthecodefilesbyfollowingthesesteps:

1. Loginorregistertoourwebsiteusingyoure-mailaddressandpassword.2. HoverthemousepointerontheSUPPORTtabatthetop.3. ClickonCodeDownloads&Errata.4. EnterthenameofthebookintheSearchbox.5. Selectthebookforwhichyou'relookingtodownloadthecodefiles.6. Choosefromthedrop-downmenuwhereyoupurchasedthisbookfrom.7. ClickonCodeDownload.

YoucanalsodownloadthecodefilesbyclickingontheCodeFilesbuttononthebook'swebpageatthePacktPublishingwebsite.Thispagecanbeaccessedbyenteringthebook'snameintheSearchbox.PleasenotethatyouneedtobeloggedintoyourPacktaccount.

Oncethefileisdownloaded,pleasemakesurethatyouunziporextractthefolderusingthelatestversionof:

WinRAR/7-ZipforWindowsZipeg/iZip/UnRarXforMac7-Zip/PeaZipforLinux

ThecodebundleforthebookisalsohostedonGitHubathttps://github.com/PacktPublishing/ASP.NET-Core-1.0-High-PerformanceWealsohaveothercodebundlesfromourrichcatalogofbooksandvideosavailableathttps://github.com/PacktPublishing/.Checkthemout!

Page 30: ASP.NET Core 1.0 High Performance

ErrataAlthoughwehavetakeneverycaretoensuretheaccuracyofourcontent,mistakesdohappen.Ifyoufindamistakeinoneofourbooks-maybeamistakeinthetextorthecode-wewouldbegratefulifyoucouldreportthistous.Bydoingso,youcansaveotherreadersfromfrustrationandhelpusimprovesubsequentversionsofthisbook.Ifyoufindanyerrata,pleasereportthembyvisitinghttp://www.packtpub.com/submit-errata,selectingyourbook,clickingontheErrataSubmissionFormlink,andenteringthedetailsofyourerrata.Onceyourerrataareverified,yoursubmissionwillbeacceptedandtheerratawillbeuploadedtoourwebsiteoraddedtoanylistofexistingerrataundertheErratasectionofthattitle.

Toviewthepreviouslysubmittederrata,gotohttps://www.packtpub.com/books/content/supportandenterthenameofthebookinthesearchfield.TherequiredinformationwillappearundertheErratasection.

Page 31: ASP.NET Core 1.0 High Performance

PiracyPiracyofcopyrightedmaterialontheInternetisanongoingproblemacrossallmedia.AtPackt,wetaketheprotectionofourcopyrightandlicensesveryseriously.IfyoucomeacrossanyillegalcopiesofourworksinanyformontheInternet,pleaseprovideuswiththelocationaddressorwebsitenameimmediatelysothatwecanpursuearemedy.

Pleasecontactusatcopyright@packtpub.comwithalinktothesuspectedpiratedmaterial.

Weappreciateyourhelpinprotectingourauthorsandourabilitytobringyouvaluablecontent.

Page 32: ASP.NET Core 1.0 High Performance

QuestionsIfyouhaveaproblemwithanyaspectofthisbook,[email protected],andwewilldoourbesttoaddresstheproblem.

Page 33: ASP.NET Core 1.0 High Performance

Chapter1.WhyPerformanceIsaFeatureThisisanexcitingtimetobeaC#developer.Microsoftisinthemiddleofoneofthebiggestchangesinitshistory,anditisembracingopensourcesoftware.TheASP.NETand.NETframeworksarebeingrebuiltfromthegrounduptobecomponentized,cross-platform,andopensource.

ASP.NETCore1.0and.NETCore1.0(previouslycalledASP.NET5and.NETCore5)embracemanyideasfrompopularopensourceprojects,suchasGo'sabilitytoproduceastatically-linked,standalonebinary.Youcannowcompileasinglenativeexecutablethatisfreeofanyexternaldependenciesandrunitonasystemwithout.NETinstalled.

TheASP.NETModelViewController(MVC)webapplicationframework,whichisnowpartofASP.NETCore1.0,borrowsheavilyfromRubyonRailsandMicrosoftiskeeninpromotingtools,suchasNode.js,Grunt,gulp,andYeoman.ThereisalsoTypeScript,whichisastatically-typedversionofJavaScriptthatwasdevelopedatMicrosoft.

Byreadingthisbook,youwilllearnhowtowritehigh-performancesoftwareusingthesenew.NETCoretechnologies.You'llbeabletomakeyourwebapplicationsresponsivetoinputandscalabletodemand.

We'llfocusonthelatestCoreversionsof.NET.Yet,manyofthesetechniquesalsoapplytopreviousversions,andtheywillbeusefulforwebapplicationdevelopmentingeneral(inanylanguageorframework).

Understandinghowallofthesenewframeworksandlibrariesfittogethercanbeabitconfusing.We'llpresentthevariousavailableoptionswhilestillusingthenewesttechnology,guidingyoudownthepathtohigh-speedsuccess,andavoidingperformancepitfalls.

Afterfinishingthisbook,youwillunderstandwhatproblemscanoccurwhenwebapplicationsaredeployedatscale(todistributedinfrastructure)andknowhowtoavoidormitigatetheseissues.Youwillgaintheexperienceofhowtowritehigh-performanceapplicationswithoutlearningaboutissuesthehardway.

Inthischapter,wewillcoverthefollowingtopics.

PerformanceasafeatureThecommonclassesofperformanceissuesBasichardwareknowledgeMicrosofttoolsandalternativesNew.NETnamingandcompatibility

Page 34: ASP.NET Core 1.0 High Performance

PerformanceasafeatureYoumayhavepreviouslyheardaboutthepracticeoftreatingperformanceasafirst-classfeature.Traditionally,performance(alongwiththingssuchassecurity,availabilityanduptime)wasonlyconsideredaNon-FunctionalRequirement(NFR)andusuallyhadsomearbitrarymade-upmetricsthatneededtobefulfilled.Youmayhaveheardtheterm"performant"before.Thisisthequalityofperformingwelland,often,iscapturedinrequirementswithoutquantification,providingverylittlevalue.Itisbettertoavoidthissortofcorporatejargonwhencorrespondingwithclientsorusers.

Usingtheoutdatedwaterfallmethodofdevelopment,theseNFRswereinevitablyleftuntiltheend,anddroppedfromanover-budgetandlateprojectinordertogetthefunctionalrequirementscompleted.Thisresultedinasubstandardproductthatwasunreliable,slow,andofteninsecure(asreliabilityandsecurityarealsooftenneglectedNFRs).Thinkabouthowmanytimesyou'refrustratedatsoftwarethatlagsbehindinrespondingtoyourinput.Perhaps,youusedaticket-vendingmachineoraself-servicecheckoutthatisunresponsivetothepointofbeingunusable.

Thereisabetterway.Bytreatingperformanceasafeatureandconsideringitateverystageofyouragiledevelopmentprocess,youcangetusersandcustomerstoloveyourproduct.Whensoftwarerespondsquickerthanausercanperceive,itisadelighttouse,andthisdoesn'tslowthemdown.Whenthereisnoticeablelag,thenusersneedtoadjusttheirbehaviortowaitforthemachineinsteadofworkingattheirownpace.

Computershaveincredibleamountsofprocessingpowertoday,andtheynowpossessmanymoreresourcesthantheydidevenjustafewyearsago.So,whydowestillhavesoftwarethatisnoticeablyslowatresponding,whencomputersaresofastandcancalculatemuchquickerthanpeoplecan?Theanswertothisispoorlywrittensoftwarethatdoesnotconsiderperformance.Whydoesthishappen?Thereasonisthatoftenthesignsofpoorperformancearenotvisibleindevelopment,andtheyonlyappearwhendeployed.However,ifyouknowwhattolookfor,thenyoucanavoidtheseproblemsbeforereleasingyoursoftwaretotheproductionenvironment.

Thisbookwillshowyouhowtowritesoftwarethatisajoytouseandneverkeepstheuserwaitingoruninformed.Youwilllearnhowtomakeproductsthatuserswillloveinsteadofproductsthatfrustratethemallthetime.

Page 35: ASP.NET Core 1.0 High Performance

CommonclassesofperformanceproblemsLet'stakealookatsomecommonareasofperformanceproblemsandseewhethertheymatterornot.Wewillalsolearnwhyweoftenmisstheseissuesduringdevelopment.

Page 36: ASP.NET Core 1.0 High Performance

LanguageconsiderationsPeopleoftenfocusonthespeedoftheprogramminglanguagethatisused.However,thisoftenmissesthepoint.Thisisaverysimplisticviewthatglossesoverthenuancesoftechnologychoices.Itiseasytowriteslowsoftwareinanylanguage.

Withthehugeamountsofprocessingspeedthatisavailabletoday,relatively"slow"interpretedlanguagescanoftenbefastenough,andtheincreaseindevelopmentspeedisworthit.Itisimportanttounderstandtheargumentsandthetrade-offsinvolvedevenifbyreadingthisbookyouhavealreadydecidedtouseC#and.NET.

Thewaytowritethefastestsoftwareistogetdowntothemetalandwriteinassembler(orevenmachinecode).Thisisextremelytimeconsuming,requiresexpertknowledge,andtiesyoutoaparticularprocessorarchitectureandinstructionset;therefore,werarelydothisthesedays.Ifthishappens,thenit'sonlydoneforverynicheapplications(suchasvirtualrealitygames,scientificdatacrunching,andsometimesembeddeddevices)andusuallyonlyforatinypartofthesoftware.

Thenextlevelofabstractionupiswritinginalanguage,suchasGo,C,orC++,andcompilingthecodetorunonthemachine.Thisisstillpopularforgamesandotherperformance-sensitiveapplications,butyouoftenhavetomanageyourownmemory(whichcancausememoryleaksorsecurityissues,suchasbufferoverflows).

Alevelaboveissoftwarethatcompilestoanintermediatelanguageorbytecodeandrunsonavirtualmachine.ExamplesofthisareJava,Scala,Clojure,and,ofcourse,C#.Memorymanagementisnormallytakencareof,andthereisusuallyaGarbageCollector(GC)totidyupunusedreferences(GoalsohasaGC).Theseapplicationscanrunonmultipleplatforms,andtheyaresafer.However,youcanstillgetneartonativeperformanceintermsofexecutionspeed.

Abovetheseareinterpretedlanguages,suchasRuby,Python,andJavaScript.Theselanguagesarenotusuallycompiled,andtheyarerunline-by-linebyaninterpreter.Theyusuallyrunslowerthanacompiledlanguage,butthisisoftennotaproblem.Amoreseriousconcerniscatchingbugswhenusingdynamictyping.Youwon'tbeabletoseeanerroruntilyouencounterit,whereasmanyerrorscanbecaughtatcompiletimewhenusingstatically-typedlanguages.

Itisbesttoavoidgenericadvice.YoumayhearanargumentagainstusingRubyonRails,citingtheexampleofTwitterhavingtomigratetoJavaforperformancereasons.Thismaywellnotbeaproblemforyourapplication,andindeedhavingthepopularityofTwitterwouldbeaniceproblemtohave.AbiggerconcernwhenrunningRailsmaybethelargememoryfootprint,makingitexpensivetorunoncloudinstances.

Thissectionisonlytogiveyouataste,andthemainlessonisthatnormally,languagedoesn'tmatter.Itisnotusuallythelanguagethatmakesaprogramslow,it'spoordesignchoices.C#offersanicebalancebetweenspeedandflexibilitythatmakesitsuitableforawiderangeofapplications,especiallyserver-sidewebapplications.

Page 37: ASP.NET Core 1.0 High Performance

TypesofperformanceproblemsTherearemanytypesofperformanceproblems,andmostofthemareindependentoftheprogramminglanguagethatisused.Alotoftheseresultfromhowthecoderunsonthecomputer,andwewillcovertheimpactofthislateroninthechapter.

Wewillbrieflyintroducecommonperformanceproblemshereandwillcovertheminmoredetailinlaterchaptersofthisbook.Issuesthatyoumayencounterwillusuallyfallintoafewsimplecategories,includingthefollowing:

Latency:MemorylatencyNetworklatencyDiskandI/OlatencyChattiness/handshakes

Bandwidth:ExcessivepayloadsUnoptimizeddataCompression

Computation:WorkingontoomuchdataCalculatingunnecessaryresultsBruteforcingalgorithms

Doingworkinthewrongplace:SynchronousoperationsthatcouldbedoneofflineCachingandcopingwithstaledata

Whenwritingsoftwareforaplatform,youareusuallyconstrainedbytworesources.Thesearethecomputationprocessingspeedandaccessingremote(totheprocessor)resources.

Processingspeedisrarelyalimitingfactorthesedays,andthiscouldbetradedforotherresources,forexample,compressingsomedatatoreducethenetworktransfertime.

Accessingremoteresources,suchasmainmemory,disk,andthenetworkwillhavevarioustimecosts.Itisimportanttounderstandthatspeedisnotasinglevalue,andithasmultipleparameters.Themostimportantofthesearebandwidthand,crucially,latency.

Latencyisthelagintimebeforetheoperationstarts,whereasbandwidthistherateatwhichdataistransferredoncetheoperationstarts.Postingaharddrivehasaveryhighbandwidth,butitalsohasveryhighlatency.Thiswouldmakeitveryslowtosendlotsoftextfilesbackandforth,butperhaps,thisisagoodchoicetosendalargebatchof3Dvideos(dependingontheWeissmanscore).Amobilephonedataconnectionmaybebetterforthetextfiles.

Althoughthisisacontrivedexample,thesameconcernsareapplicabletoeverylayerofthecomputingstackoftenwithsimilarordersofmagnitudeintimedifference.Theproblemisthatthe

Page 38: ASP.NET Core 1.0 High Performance

differencesaretooquicktoperceive,andweneedtousetoolsandsciencetoseethem.

Thesecrettosolvingperformanceproblemsisingainingadeeperunderstandingofthetechnologyandknowingwhathappensatthelowerlevels.Youshouldappreciatewhattheframeworkisdoingwithyourinstructionsatthenetworklevel.It'salsoimportanttohaveabasicgraspofhowthesecommandsrunontheunderlyinghardware,andhowtheyareaffectedbytheinfrastructurethattheyaredeployedto.

Whenperformancematters

Performanceisnotalwaysimportantineverysituation.Learningwhenperformancedoesanddoesn'tmatterisanimportantskilltoacquire.Ageneralruleofthumbisthatiftheuserhastowaitforsomethingtohappen,thenitshouldperformwell.Ifthisissomethingthatcanbeperformedasynchronously,thentheconstraintsarenotasstrict,unlessanoperationissoslowthatittakeslongerthanthetimewindowforit;forexample,anovernightbatchjobonanoldfinancialservicesmainframe.

Agoodexamplefromawebapplicationstandpointisrenderinguserviewversussendinge-mail.Itisacommon,yetnaïve,practicetoacceptaformsubmissionandsendane-mail(orworse,manye-mails)beforereturningtheresult.Yet,unlikeadatabaseupdate,ane-mailisnotsomethingthathappensalmostinstantly.Therearemanystagesoverwhichwehavenocontrolthatwilldelayane-mailinreachingauser.Therefore,thereisnoneedtosendane-mailbeforereturningtheresultoftheform.Youcandothisofflineandasynchronouslyaftertheresultoftheformsubmissionisreturned.

Theimportantthingtorememberhereisthatitistheperceptionofperformancethatmattersandnotabsoluteperformance.Itcanbebettertonotdosomework(oratleastdeferit)ratherthanspeeditup.

Thismaybecounterintuitive,especiallyconsideringhowindividualcomputeroperationscanbetooquicktoperceive.However,themultiplyingfactorisscale.Oneoperationmayberelativelyquick,butmillionsofthemmayaccumulatetoavisibledelay.Optimizingthesewillhaveacorrespondingeffectduetothemagnification.Improvingcodethatrunsinatightlooporforeveryuserisbetterthanfixingaroutinethatrunsonlyonceaday.

Slowerissometimesbetter

Insomesituations,processesaredesignedtobeslow,andthisisessentialtotheiroperationandsecurity.Agoodexampleofthis,whichmaybehitinprofiling,ispasswordhashingorkeystretching.Asecurepasswordhashingfunctionshouldbeslowsothatthepassword,which(despitebeingbadpractice)mayhavebeenreusedonotherservices,isnoteasilyrecovered.

Weshouldnotusegenerichashingfunctions,suchasMD5,SHA1,andSHA256,tohashpasswordsbecausetheyaretooquick.SomebetteralgorithmsthataredesignedforthistaskarePBKDF2andbcrypt,orevenArgon2fornewprojects.Alwaysremembertouseauniquesaltperpasswordtoo.Wewon'tgointoanymoredetailshere,butyoucanclearlyseethatspeeding

Page 39: ASP.NET Core 1.0 High Performance

uppasswordhashingwouldbebad,andit'simportanttoidentifywheretoapplyoptimizations.

Whyissuesaremissed

Oneofthemainreasonsthatperformanceissuesarenotnoticedindevelopmentisthatsomeproblemsarenotperceivableonadevelopmentsystem.Issuesmaynotoccuruntillatencyincreases.Thismaybebecausealargeamountofdatawasloadedintothesystemandretrievingaspecificrecordtakeslonger.Thismayalsobebecauseeachpieceofthesystemisdeployedtoaseparateserver,increasingthenetworklatency.Whenthenumberofusersaccessingaresourceincreases,thenthelatencywillalsoincrease.

Forexample,wecanquicklyinsertarowintoanemptydatabaseorretrievearecordfromasmalltable,especiallywhenthedatabaseisrunningonthesamephysicalmachineasthewebserver.Whenawebserverisononevirtualmachineandthebigdatabaseserverisonanother,thenthetimetakenforthisoperationcanincreasedramatically.

Thiswillnotbeaproblemforonesingledatabaseoperation,whichappearsjustasquicktoauserinbothcases.However,ifthesoftwareispoorlywrittenandperformshundredsoreventhousandsofdatabaseoperationsperrequest,thenthisquicklybecomesslow.

Scalethisuptoalltheusersthatawebserverdealswith(andallofthewebservers)andthiscanbearealproblem.Adevelopermaynotnoticethatthisproblemexistsifthey'renotlookingforit,asthesoftwareperformswellontheirworkstation.Toolscanhelpinidentifyingtheseproblemsbeforethesoftwareisreleased.

Measuring

Themostimportanttakeawayfromthisbookistheimportanceofmeasuring.Youneedtomeasureproblemsoryoucan'tfixthem.Youwon'tevenknowwhenyouhavefixedthem.Measurementisthekeytofixingperformanceissuesbeforetheybecomenoticeable.Slowoperationscanbeidentifiedearlyon,andthentheycanbefixed.

However,notalloperationsneedoptimizing.It'simportanttokeepasenseofperspective,butyoushouldunderstandwherethechokepointsareandhowtheywillbehavewhenmagnifiedbyscale.We'llcovermeasuringandprofilinginthenextchapter.

Page 40: ASP.NET Core 1.0 High Performance

ThebenefitsofplanningaheadByconsideringperformancefromtheverybeginning,itischeaperandquickertofixissues.Thisistrueformostproblemsinsoftwaredevelopment.Theearlieryoucatchabug,thebetter.Theworsttimetofindabugisonceitisdeployedandthenbeingreportedbyyourusers.

Performancebugsarealittledifferentwhencomparedtofunctionalbugsbecauseoften,theyonlyrevealthemselvesatscale,andyouwon'tnoticethembeforealivedeploymentunlessyougolookingforthem.Youcanwriteintegrationandloadteststocheckperformance,whichwewillcoverlaterinthisbook.

Page 41: ASP.NET Core 1.0 High Performance

UnderstandinghardwareRememberthatthereisacomputerincomputerscience.Itisimportanttounderstandwhatyourcoderunsonandtheeffectsthatthishas,thisisn'tmagic.

Page 42: ASP.NET Core 1.0 High Performance

StorageaccessspeedsComputersaresofastthatitcanbedifficulttounderstandwhichoperationisaquickoperationandwhichisaslowone.Everythingappearsinstant.Infact,anythingthathappensinlessthanafewhundredmillisecondsisimperceptibletohumans.However,certainthingsaremuchfasterthanothersare,andyouonlygetperformanceissuesatscalewhenmillionsofoperationsareperformedinparallel.

Therearevariousdifferentresourcesthatcanbeaccessedbyanapplication,andaselectionofthesearelisted,asfollows:

CPUcachesandregisters:L1cacheL2cacheL3cache

RAMPermanentstorage:

LocalSolidStateDrive(SSD)LocalHardDiskDrive(HDD)

Networkresources:LocalAreaNetwork(LAN)RegionalnetworkingGlobalinternetworking

VirtualMachines(VMs)andcloudinfrastructureservicescouldaddmorecomplications.Thelocaldiskthatismountedonamachinemayinfactbeasharednetworkdiskandrespondmuchslowerthanarealphysicaldiskthatisattachedtothesamemachine.Youmayalsohavetocontendwithotherusersforresources.

Inordertoappreciatethedifferencesinspeedbetweenthevariousformsofstorage,considerthefollowinggraph.Thisshowsthetimetakentoretrieveasmallamountofdatafromaselectionofstoragemediums:

Page 43: ASP.NET Core 1.0 High Performance

Thisgraphhasalogarithmicscale,whichmeansthatthedifferencesareverylarge.Thetopofthegraphrepresentsonesecondoronebillionnanoseconds.SendingapacketacrosstheAtlanticOceanandbacktakesroughly150milliseconds(ms)or150millionnanoseconds(ns),andthisismainlylimitedbythespeedoflight.Thisisstillfarquickerthanyoucanthinkabout,anditwillappearinstantaneous.Indeed,itcanoftentakelongertopushapixeltoascreenthantogetapackettoanothercontinent.

ThenextlargestbaristhetimethatittakesaphysicalHDDtomovethereadheadintopositionto

Page 44: ASP.NET Core 1.0 High Performance

startreadingdata(10ms).Mechanicaldevicesareslow.

ThenextbardownishowlongittakestorandomlyreadasmallblockofdatafromalocalSSD,whichisabout150microseconds.ThesearebasedonFlashmemorytechnology,andtheyareusuallyconnectedinthesamewayasaHDD.

Thenextvalueisthetimetakentosendasmalldatagramof1KB(1kilobyteor8kilobits)overagigabitLAN,whichisjustunder10microseconds.Thisistypicallyhowserversareconnectedinadatacenter.Notehowthenetworkitselfisprettyquick.Thethingthatreallymattersiswhatyouareconnectingtoattheotherend.Anetworklookuptoavalueinmemoryonanothermachinecanbemuchquickerthanaccessingalocaldrive(asthisisaloggraph,youcan'tjuststackthebars).

ThisbringsusontomainmemoryorRAM.Thisisfast(about100nsforalookup),andthisiswheremostofyourprogramwillrun.However,thisisnotdirectlyconnectedtotheCPU,anditisslowerthantheondiecaches.RAMcanbelarge,oftenlargeenoughtoholdallofyourworkingdataset.However,itisnotasbigasdiskscanbe,anditisnotpermanent.Itdisappearswhenthepowerislost.

TheCPUitselfwillcontainsmallcachesfordatathatiscurrentlybeingworkedon,whichcanrespondinlessthan10ns.ModernCPUsmayhaveuptothreeorevenfourcachesofincreasingsizeandlatency.Thefastest(lessthan1nstorespond)istheLevel1(L1)cache,butthisisalsousuallythesmallest.IfyoucanfityourworkingdataintothesefewMBorKBincaches,thenyoucanprocessitveryquickly.

Page 45: ASP.NET Core 1.0 High Performance

ScalingapproachchangesFormanyyears,thespeedandprocessingcapacityofcomputersincreasedatanexponentialrate.ThiswasknownasMoore'sLaw,namedafterGordonMooreofIntel.Sadly,thiseraisnoMoore(sorry).Single-coreprocessorspeedshaveflattenedout,andthesedaysincreasesinprocessingabilitycomefromscalingouttomultiplecores,multipleCPUs,andmultiplemachines(bothvirtualandphysical).Multithreadedprogrammingisnolongerexotic,itisessential.Otherwise,youcannothopetogobeyondthecapacityofasinglecore.ModernCPUstypicallyhaveatleastfourcores(evenformobiles).Addinatechnologysuchashyper-threading,andyouhaveatleasteightlogicalCPUstoplaywith.Naïveprogrammingwillnotbeabletofullyutilizethese.

Traditionally,performance(andredundancy)wasprovidedbyimprovingthehardware.Everythingranonasingleserverormainframe,andthesolutionwastousefasterhardwareandduplicateallcomponentsforreliability.Thisisknownasverticalscaling,andithasreachedtheendofitslife.Itisveryexpensivetoscalethiswayandimpossiblebeyondacertainsize.Thefutureisindistributed-horizontalscalingusingcommodityhardwareandcloudcomputingresources.Thisrequiresthatwewritesoftwareinadifferentmannerthanwedidpreviously.Traditionalsoftwarecan'ttakeadvantageofthisscalinglikeitcaneasilyusetheextracapabilitiesandspeedofanupgradedcomputerprocessor.

Therearemanytrade-offsthathavetobemadewhenconsideringperformance,anditcansometimesfeellikemoreofablackartthanascience.However,takingascientificapproachandmeasuringresultsisessential.Youwilloftenhavetobalancememoryusageagainstprocessingpower,bandwidthagainststorage,andlatencyagainstthroughput.

Anexampleisdecidingwhetheryoushouldcompressdataontheserver(includingwhatalgorithmsandsettingstouse)orsenditrawoverthewire.Thiswilldependonmanyfactors,includingthecapacityofthenetworkandthedevicesatbothends.

Page 46: ASP.NET Core 1.0 High Performance

ToolsandcostsLicensingofMicrosoftproductshashistoricallybeenaminefieldofcomplexity.Youcanevensitforanofficialexamonitandgetaqualification.Microsoft'srecentmovetowardopensourcepracticesisveryencouraging,asthebiggestbenefitofopensourceisnotthefreemonetarycostbutthatyoudon'thavetothinkaboutthelicensingcosts.Youcanalsofixissues,andwithapermissivelicense(suchasMIT),youdon'thavetoworryaboutmuch.Thetimecostsandcognitiveloadofworkingoutlicensingimplicationsnowandinthefuturecandwarfthefinancialsumsinvolved(especiallyforasmallcompanyorstartup).

Page 47: ASP.NET Core 1.0 High Performance

ToolsDespitethenew.NETframeworkbeingopensource,manyofthetoolsarenot.SomeeditionsofVisualStudioandSQLServercanbeveryexpensive.Withthenewlicensingpracticeofsubscriptions,youwillloseaccessifyoustoppaying,andyouarerequiredtosignintodevelop.Previously,youcouldkeepusingexistingversionslicensedfromaMicrosoftDeveloperNetwork(MSDN)orBizSparksubscriptionafteritexpiredandyoudidn'tneedtosignin.

Withthisinmind,wewilltrytosticktothefree(community)editionsofVisualStudioandtheExpressversionofSQLServerunlessthereisafeaturethatisessentialtothelesson,whichwewillhighlightwhenitoccurs.Wewillalsouseasmanyfreeandopensourcelibraries,frameworks,andtoolsaspossible.

TherearemanyalternativeoptionsforlotsofthetoolsandsoftwarethataugmentstheASP.NETecosystem,andyoudon'tjustneedtousethedefaultMicrosoftproducts.ThisisknownastheALT.NET(alternative.NET)movement,whichembracespracticesfromtherestoftheopensourceworld.

Page 48: ASP.NET Core 1.0 High Performance

LookingatsomealternativetoolsForversioncontrol,gitisaverypopularalternativetoTeamFoundationServer(TFS).Thisisintegratedintomanytools(includingVisualStudio)andservices,suchasGitHuborGitLab.Mercurial(hg)isalsoanoption.However,githasgainedthemostdevelopermindshare.VisualStudioOnlineoffersbothgitandTFSintegration.

PostgreSQLisafantasticopensourcerelationaldatabase,anditworkswithmanyObjectRelationalMappers(O/RMs),includingEntityFramework(EF)andNHibernate.Dapperisagreat,andhigh-performance,alternativetoEFandotherbloatedO/RMs.ThereareplentyofNoSQLoptionsthatareavailabletoo;forexample,RedisandMongoDB.

OthercodeeditorsandIntegratedDevelopmentEnvironments(IDEs)areavailable,suchasVisualStudioCodebyMicrosoft,whichalsoworksonAppleMacOSX.ASP.NETCore1.0(previouslyASP.NET5)runsonLinux(onMonoandCoreCLR).Therefore,youdon'tneedWindows(althoughNanoServermaybeworthinvestigating).

RabbitMQisabrilliantopensourcemessagequeuingserverthatiswritteninErlang(whichWhatsAppalsouses).ThisisfarbetterthanMicrosoftMessageQueuing(MSMQ),whichcomeswithWindows.Hostedservicesarereadilyavailable,forexample,CloudAMQP.

TheauthorhasbeenalongtimeMacuser(sincethePowerPCdays),andhehasrunLinuxserverssincewellbeforethis.It'spositivetoseeOSXbecomepopularandtoobservetheriseofLinuxonAndroidsmartphonesandcheapcomputers,suchastheRaspberryPi.YoucanrunWindows10onaRaspberryPi2and3,butthisisnotafulloperatingsystemandonlymeanttorunInternetofThings(IoT)devices.HavingusedWindowsprofessionallyforalongtime,developinganddeployingwithMacandLinux,andseeingwhatperformanceeffectsthisbringsisaninterestingopportunity.

Althoughnotopensource(oralwaysfree),itisworthmentioningJetBrainsproducts.TeamCityisaverygoodbuildandContinuousIntegration(CI)serverthathasafreetier.ReSharperisanawesomepluginforVisualStudio,whichwillmakeyouabettercoder.They'realsoworkingonaC#IDEcalledProjectRiderthatpromisestobegood.

ThereisaproductcalledOctopusDeploy,whichisextremelyusefulforthedeploymentof.NETapplications,andithasafreetier.Regardingcloudservices,AmazonWebServices(AWS)isanobviousalternativetoAzure,eveniftheAWSWindowssupportleavessomethingtobedesired.Therearemanyotherhostsavailable,anddedicatedserverscanoftenbecheaperforasteadyloadifyoudon'tneedthedynamicscalingofthecloud.

Muchofthisisbeyondthescopeofthisbook,butyouwouldbewisetoinvestigatesomeofthesetools.Thepointisthatthereisalwaysachoiceabouthowtobuildasystemfromthehugerangeofcomponentsavailable,especiallywiththenewversionofASP.NET.

Page 49: ASP.NET Core 1.0 High Performance

Thenew.NETThenewASP.NETandthe.NETFrameworkthatitreliesuponwererewrittentobeopensourceandcross-platform.ThisworkwascalledASP.NET5whileindevelopment,butthishassincebeenrenamedtoASP.NETCore1.0toreflectthatit'sanewproductwithastrippeddownsetoffeatures.Similarly,.NETCore5isnow.NETCore1.0,andEntityFramework7isnowEntityFrameworkCore1.0.

ThewebapplicationframeworkthatwascalledASP.NETMVChasbeenmergedintoASP.NETCore,althoughit'sapackagethatcanbeaddedlikeanyotherdependency.ThelatestversionofMVCis6and,alongwithWebAPI2,thishasbeencombinedintoasingleproduct,calledASP.NETCore.MVCandWebAPIaren'tnormallyreferredtodirectlyanymoreastheyaresimplyNuGetpackagesthatareusedbyASP.NETCore.NotallfeaturesareavailableinthenewCoreframeworksyet,andthefocusisonserver-sidewebapplicationstostartwith.

Allthesedifferentnamescanbeperplexing,butnamingthingsishard.AvariationofPhilKarlton'sfamousquotegoeslikethis:

"ThereareonlytwohardthingsinComputerScience:cacheinvalidation,namingthings,andoff-by-oneerrors."

We'velookedatnaminghere,andwe'llgettocachinglateroninthisbook.

Itcanbealittleconfusingunderstandinghowalloftheseversionsfittogether.Thisisbestexplainedwithadiagramlikethefollowing,whichshowshowthelayersinteract:

ASP.NETCore1.0canrunagainsttheexisting.NETFramework4.6orthenew.NETCore1.0framework.Similarly,.NETCorecanrunonWindows,MacOSX,andLinux,buttheold.NETonlyrunsonWindows.

ThereisalsotheMonoframework,whichhasbeenomittedforclarity.Thiswasaprevious

Page 50: ASP.NET Core 1.0 High Performance

projectthatallowed.NETtorunonmultipleplatforms.MonowasrecentlyacquiredbyMicrosoft,anditwasopensourced(alongwithotherXamarinproducts).Therefore,youshouldbeabletorunASP.NETCoreusingMonoonanysupportedoperatingsystem.

.NETCorefocusesonweb-applicationdevelopmentandserver-sideframeworks.Itisnotasfeaturefilledastheexisting.NETFramework.Ifyouwritenative-graphicaldesktopapplications,perhapsusingWindowsPresentationFoundation(WPF),thenyoushouldstickwith.NET4.6.

Asthisbookismainlyaboutweb-applicationdevelopment,wewillusethelatestCoreversionsofallsoftware.Wewillinvestigatetheperformanceimplicationsofvariousoperatingsystemsandarchitectures.Thisisparticularlyimportantifyourdeploymenttargetisacomputer,suchastheRaspberryPi,whichusesaprocessorwithanARMarchitecture.Italsohaslimitedmemory,whichisimportanttoconsiderwhenusingamanagedruntimethatincludesgarbagecollection,suchas.NET.

Page 51: ASP.NET Core 1.0 High Performance

SummaryLet'ssumupwhatwecoveredinthisintroductorychapterandwhatwewillcoverinthenextchapter.Weintroducedtheconceptoftreatingperformanceasafeature,andwecoveredwhythisisimportant.Wealsobrieflytouchedonsomecommonperformanceproblemsandwhyweoftenmisstheminthesoftwaredevelopmentprocess.We'llcovertheseinmoredetaillateroninthisbook.

Weshowedtheperformancedifferencesbetweenvarioustypesofstoragehardware.Wehighlightedtheimportanceofknowingwhatyourcoderunsonand,crucially,whatitwillrunonwhenyourusersseeit.Wetalkedabouthowtheprocessofscalingsystemshaschangedfromwhatitusedtobe,howscalingisnowperformedhorizontallyinsteadofvertically,andhowyoucantakeadvantageofthisinthearchitectingofyourcodeandsystems.

Weshowedyouthetoolsthatyoucanuseandthelicensingimplicationsofsomeofthem.Wealsoexplainedthenewworldof.NETandhowtheselatestframeworksfitinwiththestableones.Wetoucheduponwhymeasurementisvitallyimportant.Inthenextchapter,we'llexpandonthisandshowyouhowtomeasureyoursoftwaretoseewhetherit'sslow.

Page 52: ASP.NET Core 1.0 High Performance

Chapter2.MeasuringPerformanceBottlenecksMeasurementisthemostcrucialaspectofbuildinghighperformancesystems.Youcan'tchangewhatyoucan'tmeasure,becauseyouwon'tknowwhateffectyourchangehashad,ifany.Withoutmeasuringyourapplicationyouwon'tknowifit'sperformingwell.

Ifyouonlygobywhenyoursoftwarefeelsslowthenyouhaveleftittoolate.Youarereactivelyfixingaproblemratherthanproactivelyavoidingone.Youmustmeasuretoachievegoodperformanceeventhoughit'sthefeelthatmatterstoauser.

Somebooksleavemeasurement,analysis,andprofilinguntiltheend.Yetthisisthefirstthingthatshouldbeconsidered.It'seasytofixthewrongproblemandoptimizeareasthatarenothavingperformancedifficulties.

Inthischapterwewillcoverthefollowingtopics.

StructuredQueryLanguage(SQL)databaseprofilingSQLServerProfilerMiniProfiler

WebapplicationprofilingGlimpseIntegratedDevelopmentEnvironment(IDE)profilers

HTTPmonitoringBrowserdevelopertoolsFiddlerproxy

NetworkmonitoringMicrosoftmessageanalyzerWireshark

Scientificmethodandrepeatability

Thischapterwillshowyouhowtomeasureifthereareperformanceissuesandwheretheyareoccurring.Wewilldescribethetoolsthatcangiveyouthisinformationanddemonstratehowtousethemeffectivelyandcorrectly.We'llalsoshowyouhowtorepeatyourexperimentsconsistentlysothatyoucantellifyouhavefixedaproblemonceyou'veidentifiedit.

Wewillcovermeasurementagaintowardstheendofthebook,buttherewe'llfocusoncontinuousautomatedmonitoringtoavoidregressions.Thischapterwillfocusmoreonmanualtestingtoidentifypotentialperformanceproblemsduringdevelopmentanddebugging.

Page 53: ASP.NET Core 1.0 High Performance

ToolsGooddebuggingtoolsareessentialindiscoveringwhereproblemslie.Youcanwriteyourowncrudetimingcodeandwewillshowyouhow.However,purposebuilttoolsaremuchnicertoworkwith.

Manyofthetoolsinthischapterhelpexamineareasexternaltoyourcode.Wewillcoverprofilingofcodetoo,butit'shardtoidentifyproblemsthiswayunlesstheworkispurelycomputational.Slowdownsoftenhappenbecauseofactionsyourappinitiatesoutsideofitsimmediatestack,andthesecanbehardtodebugbysimplysteppingthroughthecode.

Movingthroughyourprogramline-by-lineslowsdownexecutionsomuchthatitcanbedifficulttoidentifywhichlinesarefastandwhichareslow.Thesameapproachtakenforfixingfunctionalbugscannotalwaysbeappliedtofixperformanceissues.

Oneoftheproblemswithadoptinganewframework(suchasASP.NETCore)earlyisthatitcantakeawhilefortheexistingtoolstobeupdatedtoworkwithit.Wewillpointoutwhenthisisthecasebutthesecompatibilityproblemsshouldimproveovertime.Asmanyofthetoolsareopensource,youcouldhelpoutandcontributetothecommunity.

Page 54: ASP.NET Core 1.0 High Performance

SQLFirstoffwewillcoverSQLrelatedissues,soifyou'renotusingarelationaldatabasethenyoucanskipthisbit,perhapsifyou'reusingaNoSQLstoreoradocumentdatabaseinstead.Relationaldatabasesareaverymaturetechnologyandareflexibleintheiruses.However,itisessentialtohaveabasicknowledgeoftheSQLsyntaxandhowdatabasesworkinordertousethemeffectively.

ItcanbetemptingwhenusinganO/RMsuchasEntityFramework(EF)toignoreSQLandstayinaC#world,butacompetentdevelopershouldbeabletowriteahighperformanceSQLquery.Ignoringtherealitiesofhowadatabaseengineworkswilloftenleadtoperformanceissues.It'seasytowritecodewithanO/RMthat'stoochattywiththedatabaseandissuesfartoomanyqueriesforanoperation.Nothavingthecorrectindexesonatablewillalsoresultinpoorperformance.

Duringdevelopmentyoumaynotnoticethesemistakes,unlessyouusetoolstoidentifytheinefficienteventsoccurring.Herewewillshowyouacoupleofwaysofdoingthis.

SQLServerProfiler

SQLServerProfilerisatoolthatallowsyoutoinspectwhatcommandsarebeingexecutedonyourSQLServerdatabase.Ifyouhavethemanagementtoolsinstalledthenyoushouldalreadyhaveitonyourmachine.

1. IfyouareusingMicrosoftSQLServer,thenSQLServerProfilercanbeaccessedfromtheToolsmenuofSQLServerManagementStudio(SSMS).

2. LoadSQLServerProfilerandconnecttothedatabasethatyouareusing.NameyourtraceandselecttheTuningprofiletemplate.

Page 55: ASP.NET Core 1.0 High Performance

3. ClickRunandyoushouldseethatthetracehasbegun.Youarenowreadytorunyourcodeagainstthedatabasetoseewhatqueriesit'sactuallyexecuting.

Executingasimplequery

AsatestyoucanexecuteasimpleselectquerywithManagementStudioandtheprofilewindowshouldbefloodedwithentries.Locatethequerythatyoujustexecutedamongthenoise.Thisis

Page 56: ASP.NET Core 1.0 High Performance

easierifitstartswithacomment,asshowninthefollowingscreenshot.

TheDurationcolumnshowsthetimetakenforthequeryinmilliseconds(ms).Inthisexample,selectingthetop1000rowsfromatablecontainingoveramillionentriestook246ms.Thiswouldappearveryquick,almostinstantaneous,totheuser.Modifyingthequerytoreturnallrowsmakesitmuchslower,asshowninthefollowingscreenshot:

Page 57: ASP.NET Core 1.0 High Performance

Thequeryhasnowtakenover13seconds(13455ms)tocomplete,whichisnoticeablyslow.Thisisanextremeexample,butitisquiteacommonmistaketorequestmoredatathanneededandtofilterorsortitinapplicationcode.Thedatabaseisoftenmuchbettersuitedtothistaskandisusuallythecorrectlocationtoselectthedatayouwant.

WewillcoverspecificSQLmistakesandremediesinthefollowingchapters.However,thefirststepisknowinghowtodetectwhatisgoingonwiththecommunicationbetweenyourapplicationandthedatabase.Ifyoucan'tdetectthatyourappismakinginefficientqueriesthenitwillbedifficulttoimproveperformance.

MiniProfiler

MiniProfilerisanexcellentopensourcetoolfordebuggingdataqueries.ItsupportsSQLdatabasesandsomeNoSQLdatabases,suchasMongoandRaven.ItcameoutofStackExchange,thepeoplewhoruntheStackOverflowQ&Asite.Itembedsawidgetintoyourwebpagesthatshowsyouhowlongtheytaketogettheirdata.ItalsoshowsyoutheSQLqueriesandwarnsyouaboutcommonmistakes.AlthoughMiniProfilerstartedwith.NET,itisalsoavailableforRuby,Go,andNode.js.

Page 58: ASP.NET Core 1.0 High Performance

ThebiggestbenefitofMiniProfileroverSQLServerProfileristhatit'salwaysthere.Youdon'tneedtoexplicitlygolookingforSQLproblemsandsoitcanhighlightissuesmuchearlier.It'sevenagoodideatorunitinproduction,onlyvisibletologgedinadmins.Thisway,everytimeyouworkonthewebsiteyouwillseehowthedataaccessisperforming.Makesureyoutestfortheperformanceimpactsofthisbeforedeployingitthough.

UnfortunatelyMiniProfilerdoesn'tyetsupportASP.NETCore1.0.ItreliesontheSystem.Weblibraryanddoesn'ttieintotheOpenWebInterfacefor.NET(OWIN)stylelifecycleusedbythenewframework.HopefullyitwillsoonsupportASP.NETCore(andmaydobythetimeyoureadthis)asit'saveryusefultool.

Tip

Ifyou'reusingasupportedversionofASP.NETthenMiniProfilerishighlyrecommended.ASP.NETCoresupportisplanned,sokeepaneyeonANCLAFS.comforthelatestsupportdetails.

Duetotheselimitations,wewon'tcoverMiniProfilerintoomuchdetailbutyoucangetmoreinformationatminiprofiler.com.IfyouareusingapreviousversionofASP.NETthenyoucaninstallitintoyourprojectwiththeNuGetpackagemanager.TypeInstall-PackageMiniProfilerintothepackagemanagerPowerShellconsolewindowinVisualStudio.Thenfollowtherestofthesetupinstructionsfromthewebsite.

Page 59: ASP.NET Core 1.0 High Performance

ApplicationprofilingOftenyouwillwantabreakdownofwhereallthetimeisbeingtakenupwithinyourapplication.Therearevarioustoolsavailableforthisandwewillcoveracoupleofthemhere.

Glimpse

Glimpseisafantasticopensourceadd-onforyourwebapplication.LikeMiniProfiler,itaddsawidgettoyourwebpagessothatyoucanseeproblemsasyounavigatearoundandworkonyoursite.Itprovidesinformationsimilartoyourbrowserdevelopertoolsbutalsodelvesinsideyourserversideapplicationtoshowyouatraceofwhatactionsaretakingthemosttime.

Glimpseisavailablefromgetglimpse.comandyoucaninstallitwithNuGetforthewebframeworkandO/RMyou'reusing.ForASP.NETCorewewillneedtouseGlimpseversion2.Thisiscurrentlyabetaprerelease,butbythetimeyoureadthisitmaybestable.

UsingGlimpse

InstallingGlimpseisreallysimple,thereareonlythreesteps.

1. InstallwithNuGet.2. AddlinestoStartup.cs.3. Buildandruntheapp.

Let'shavealookatthesesteps.

Installingthepackage

Right-clickonyourwebapplicationprojectintheSolutionExplorerandselectManageNuGetPackages...toopenthegraphicalpackagemanagerwindow.SearchforGlimpse,selectit,andthenclickontheInstallbutton.IfyouwanttoinstallthebetaversionofGlimpse2,thenmakesuretheIncludeprereleasecheckboxisselected:

Page 60: ASP.NET Core 1.0 High Performance

Addcode

YouneedtoaddthreesnippetsofcodetoyourStartup.csfile.Intheusingdirectivesatthetopofthefile,addthefollowing:

usingGlimpse;

IntheConfigureServicesfunction,addthefollowing:

services.AddGlimpse();

IntheConfigurefunction,addthefollowing:

app.UseGlimpse();

Runningyourwebapplication

BuildandrunyourwebapplicationbypressingF5.Ifyouencounteraduplicatetypeerrorwhenrunningthensimplycleanthesolutionanddoafullrebuild.Youmayneedtoapplymigrationstothedatabase,butthisisjustabuttonclickinthebrowser.However,ifyouaddthistoanexistingprojectwithdata,thenyoushouldtakemorecare.

YoushouldthenlookatyourwebapplicationwiththeGlimpsebaratthebottomofthebrowserwindow,whichlookslikethefollowingscreenshot.Thebarisonelongstrip,butithasbeenbrokenupinthisscreenshottodisplayitmoreclearly:

Note

Thefirstpageloadmaytakemuchlongerthansubsequentones,soyoushouldrefreshformorerepresentativedata.However,wewon'tworryaboutthisforthepurposesofthisdemo.

MouseovereachsectionintheGlimpsetoolbartoexpanditformoreinformation.Youcanminimizeandrestoreeachsection(HTTP,HOST,orAJAX)byclickingonitstitle.

Ifyouusedthedefaultwebapplicationtemplate(andlefttheauthenticationasthedefaultindividualuseraccounts),thenyoucanregisteranewusertocausetheapplicationtoperformsomedatabaseoperations.YouwillthenseesomevaluesintheDBqueriesfield,asshowninthe

Page 61: ASP.NET Core 1.0 High Performance

followingscreenshot:

ClickontheGlimpselogotoseeahistoryofallthepagerequests.SelectonetoviewthedetailsandexpandtheSQLqueriesbyclickingonthem,whichisdisplayedinthefollowingscreenshot:

GlimpseshowsyouhowmuchtimeisspentineachlayerofyourapplicationandexactlywhichSQLqueriesarebeingrun.Inthiscase,EFCore1.0generatestheSQL.

Glimpseisveryusefultotrackdownwhereperformanceproblemslie.Youcaneasilyseehow

Page 62: ASP.NET Core 1.0 High Performance

longeachpartofthepagepipelinetakesandidentifyslowparts.

IDE

UsingtheprofilingtoolsthatarebuiltintoVisualStudio(VS)canbeveryinformativetounderstandtheCPUandmemoryusageofyourcode.Youcanalsoseethetimetakenforcertainoperations.

Whenrunningyourapplication,openthediagnostictoolswindowinVS,asshowninthefollowingscreenshot:

YoucanseetheCPUandmemoryprofiles,includingtheautomaticGarbageCollectioneventsthatareusedtofreeupmemory(themarkerjustpriortomemoryusedecreasing).Youwillbeabletoseebreakpointeventsand,ifyouhavetheenterpriseversionofVS,IntelliTraceeventsaswell.

Note

IntelliTraceisonlyavailableintheenterpriseeditionofVisualStudio.However,youcanstillusetheperformanceanddiagnostictoolsinthefreecommunityedition.

IfyouhaveIntelliTrace,thenyoucanfinditintheVSoptions,asshowninthefollowing

Page 63: ASP.NET Core 1.0 High Performance

screenshot.However,thediagnostictoolsarestillusefulwithoutthispremiumfeature:

Whenyouputinabreakpointandyourcodehitsit,thenVSwilltellyouhowlongitwassincethepreviousevent.Thisisshownintheeventslistandalsooverlaidnearthebreakpoint.

Tip

Youcan'tinstallthecommunityeditionandenterpriseeditionofVisualStudioonthesamemachine.UseaVirtualMachine(VM),forexample,withHyper-VorVirtualBox,ifyouwishtorunboth.

AlternativestoVStoolsareRedgateANTSandTelerikJustTrace.JetBrainsalsohavedotTraceanddotMemory.However,allofthesetoolscanbequiteexpensiveandwewon'tcoverthemhere.

Page 64: ASP.NET Core 1.0 High Performance

MonitoringHTTPWhendealingwithawebapplication,youwillnormallyuseHTTPastheapplicationprotocol.It'sveryusefultoknowwhatrequestsoccurbetweenthebrowsersandyourservers.

Browsers

Mostmodernbrowsershaveexcellentdevelopertools,whichincludeanetworktabtomonitorrequeststoandresponsesfromthewebserver.YoucannormallyaccessthedevtoolsbypressingF12.Thesearehandytoviewthewebtrafficandyoucanstillseeencryptedcommunicationswithoutmessingaboutwithcertificates.

ThedevtoolsinbothChromeandFirefoxaresuperb.We'llfocusonthenetworkandtimingcomponent,butwehighlyrecommendthatyoulearnallofthefeatures.Ifyouknowhowtogetthebestoutofthem,thenwebdevelopmentismucheasier.

Chrome

ThenetworkdevtoolsinChromeareveryuseful.Theyprovideagoodvisualizationoftherequesttimings,andyoucanthrottletheconnectiontoseehowitbehavesovervariousdifferentinternetconnections.Thisisparticularlyimportantformobiledevices.

AselectionofnetworkrequestsfromtheChromedevtoolsareshowninthefollowingscreenshot.Additionalcolumnsareavailableifyouright-clickontheHeadersbar:

Youcandisablethecachewithasimplecheckboxsothatthebrowserwillalwaysloadassetsfreshfromyourwebserver.Youcanalsoclickonaresourceformoreinformationandthetimingtabisveryusefultoprovideabreakdownoftheconnectioncomponents,forexample,TimeToFirstByte(TTFB).Somebasictimingdetailsfromalocalwebserverareshowninthefollowingscreenshot:

Page 65: ASP.NET Core 1.0 High Performance

Onalocalwebserver,thisbreakdownwon'tcontainmuchextrainformation,butonaremoteserveritwilldisplayotherthings,suchastheDomainNameSystem(DNS)hostnamelookup,andSSL/TLShandshake.Theseadditionalcomponentsareshowninthenextscreenshot:

Firefox

Page 66: ASP.NET Core 1.0 High Performance

FirefoxhassimilardevtoolstoChromebutwithsomeaddedfeatures.Forexample,youcaneditarequestandresendittothewebserver.TheNetworktabpresentsthesamesortofinformationasChromedoes,asshowninthefollowingscreenshot:

Thedetailviewisalsoverysimilar,includingtheTimingstab.Thistabisshowninthefollowingscreenshot:

Fiddler

Page 67: ASP.NET Core 1.0 High Performance

Sometimes,browsertoolsaren'tenough.Perhaps,youaredebugginganativeapplication,backendwebclient,ormobilebrowser.FiddlerisafreedebuggingproxythatcancaptureallHTTPtrafficbetweentheclientandserver.Withalittlebitofwork,itcanalsointerceptHTTPStraffic.Fiddlerisavailableatwww.telerik.com/fiddler.

Asthisbookfocusesonwebdevelopmentwewon'tgointomoredetail.Thebrowserdevtoolsaresuitableformostworkthesedays.TheynowfulfilalargepartoftherolethatFiddlerusedtoplaybeforetheyacquiredthesamefeatures.FiddlerisstillthereifyouneeditanditcanbehandyifyourwebservercallsanexternalHTTPAPI.AlthoughthiscanalsooftenbedebuggeddirectlyinsideVS.

Page 68: ASP.NET Core 1.0 High Performance

NetworkOccasionally,youwillneedtodebugatalowerlevelthanHTTPorSQL.Thisiswherenetworkmonitorsorpacketsnifferscomein.Perhaps,youwanttodebugaTabularDataStream(TDS)messagetoaSQLServerDBoraTLShandshaketoanSSLterminatingloadbalancer.OrmaybeyouwanttoanalyzeaSOAPwebserviceenvelopeorSimpleMailTransferProtocol(SMTP)e-mailconnectiontoseewhyit'snotworkingcorrectly.

MicrosoftMessageAnalyzer

MicrosoftMessageAnalyzersupersedesMicrosoftNetworkMonitor(Netmon)andisatooltocapturenetworktrafficonWindowssystems.Netmonrequiresyoutologoutandbackinagainafterinstallation,whereasWiresharkdoesn't.YoucanreadmoreaboutthesetwoMicrosofttoolsonline,but,forclarityandbrevity,wewillfocusonWiresharkforlow-levelnetworkmonitoring.

Wireshark

Wireshark(previouslycalledEthereal)isanopensourceandcross-platformpacketcaptureandnetworkanalysisapplication.Itisprobablythemostpopulartoolofitskindandhasmanyuses.YoucaninstallWiresharkwithoutneedingtorestartorlogoutwhichmakesitgreattodebugaliveproblemthat'shardtorecreate.YoucandownloadWiresharkfromwww.wireshark.organditrunsonWindows,MacOSX,andLinux.

Wiresharkisn'tparticularlyusefulforlocaldevelopmentasitonlycapturestrafficgoingoverthenetwork,nottolocalhost.TheonlythingyouarelikelytoseeifyourunitagainstalocalwebapplicationisVSreportingwhatyoudobacktoMicrosoft.

Tip

YoucanturnofftheCustomerExperienceImprovementProgram(CEIP)byclickingonthebuttonnexttothequicklaunchboxandselectingSettings....Bydefault,itison(it'snowopt-outratherthantheopt-inofpreviousproducts).

Clickonthefiniconbuttonatthetop-leftofWiresharktostartatrace.Thenperformsomenetworkactions,suchasloadingawebpagefromatestserver.Onceyoucapturesomepackets,clickonthestopbuttonandyoucanthenexaminethecollecteddataatyourleisure.

Note

AskyourITadministratorbeforerunningWireshark.ItcanoftenpickupsensitiveinformationoffoftheLAN,whichmaybeagainstyourITacceptableusepolicy.

ThefollowingscreenshotshowspartoftheresultsfromaWiresharkcapture.

Page 69: ASP.NET Core 1.0 High Performance

TherecanbealotofnoisewhenusingWireshark.Youwillseelow-levelnetworkpackets,suchasAddressResolutionProtocol(ARP)traffic,whichyoucanfilteroutorignore.YoumayalsoseedatafromVoIPphonesandothernetworkeddevicesordatathatisintendedforothercomputersonthenetwork.

Selectthepacketthatyouareinterestedinfromthetoppane.Themiddlepanewilldisplaythecontentsofthepacket.Youcannormallyignorethelowerlayersofthenetworkstack,suchasEthernetandTCP/IP(presentedatthetopofthelist).

Divestraightintotheapplicationlayerthatislistedlast.IfthisisaprotocolthatWiresharkrecognizes,thenitwillbreakitdownintothefieldsthatit'smadeupof.

Thebottompanedisplaysahexdumpoftherawpacket.Thisisnotnormallyasusefulastheparseddatainthemiddlepane.

Page 70: ASP.NET Core 1.0 High Performance

IfyouuseTLS/SSL(hint:youshould),thenyouwon'tseethecontentsofHTTPtraffic.Youwouldneedacopyoftheserver'sprivatekeytoseeinsidetheTLSconnection,whichwrapsandencryptstheHTTPapplicationdata.YouwillonlybeabletoseethedomainthatwasconnectedtoviatheDNSlookupandTLScertificate,notthefullURLoranypayloaddata.

UsingWiresharkisahugetopic,andtherearemanygreatresourcesavailabletolearnaboutit,bothonlineandoffline.Wewon'tgointomuchmoredetailherebecauseit'susuallynotnecessarytogodowntothislowlevelofnetworkscrutiny.However,thisisagoodtooltohaveinyourbackpocket.

Page 71: ASP.NET Core 1.0 High Performance

RollyourownSometimes,youmaywanttowriteyourownperformancemeasurementcode.Makesurethatyouhaveexhaustedallotheroptionsandinvestigatedtheavailabletoolsfirst.

Note

Perhaps,youwanttorecordtheexecutiontimeofsomeprocesstowritetoyourlogs.MaybeyouwanttosendthistoasystemsuchasLogstashthenvisualizethechangesovertimewithKibana.BotharegreatopensourceproductsfromElastic,andtheystoredataintheElasticsearchsearchserver.Youcanreadmoreaboutbothofthesetoolsatelastic.co

Youcaneasilyrecordthelengthoftimeforataskbystoringthecurrenttimebeforeitstartsandcomparingthistothecurrenttimeafteritfinishes,butthisapproachhasmanylimitations.Theactofmeasuringwillaffecttheresulttosomeextent,andtheclockisnotaccurateforshortdurations.Itcanbeusefulforreallysloweventsifyouneedtosharestatesbetweenprocessesormultipleruns,but,tobenchmark,youshouldnormallyusetheStopwatchclass.

Tip

ItisusuallybesttostoretimestampsinCoordinatedUniversalTime(UTC),whichisotherwiseknownasGreenwichMeanTime(GMT),andnametimestampsinUTC.YouwillavoidmanyissueswithtimezonesanddaylightsavingifyouuseDateTimeOffset.UtcNow(oratleastDateTime.UtcNow).Namevariablesandcolumnstoindicatethis,forexample,TimestampUtc.

UseTimeSpanforlengthsoftime,but,ifyoumustuseprimitives(suchasintegers),thenincludetheunitsinthevariableorcolumnname.Forexample,DurationInMillisecondsorTimeoutInSeconds.Thiswillhelptoavoidconfusionwhenanotherdeveloper(oryourfutureself)comestousethem.

However,tobenchmarkquickoperations,youshoulduseaStopwatch.ThisclassisintheSystem.Diagnosticsnamespace.

Ifyoutrytomeasureasinglequickevent,thenyouwillnotgetaccurateresults.Awayaroundthisistorepeatthetaskmanytimesandthentakeanaverage.Thisisusefultobenchmark,butitisnotusuallyapplicabletorealapplications.However,onceyouidentifywhatworksquickestwithatest,thenyoucanapplyittoyourownprograms.

Let'sillustratethiswithasmallexperimenttotimehowlongittakestohashapasswordwiththePBKDF2algorithm(intheSystem.Security.Cryptographynamespace).Inthiscase,theoperationundertestisnotimportant,aswearesimplyinterestedinthetimingcode.ANaïveapproachmaylooklikethefollowingcode:

vars=Stopwatch.StartNew();

pbkdf2.GetBytes(2048);

s.Stop();

Console.WriteLine($"Testduration={s.ElapsedMilliseconds}ms");

Page 72: ASP.NET Core 1.0 High Performance

Thiscodewilloutputadifferentvalueeverytimeitisrun,duetotheflawsinthemeasurementprocess.Abetterwaywouldbetorepeatthetestmanytimesandaveragetheoutput,likethefollowingcode:

vars=Stopwatch.StartNew();

for(varii=0;ii<tests;ii++)

{

pbkdf2.GetBytes(2048);

}

s.Stop();

varmean=s.ElapsedMilliseconds/tests;

Console.WriteLine($"{tests}runsmeanduration={mean}ms");

Thiscodewilloutputverysimilarresultseverytime.Thehigherthevalueoftests,themoreaccurateitwillbe,butthelongerthetestwilltake.

Note

Weusethenewconcisestring-formattingmethodhere,butyoucanusethetraditionaloverloadstoConsole.WriteLineifyouprefer.

Let'swriteaquickexampleapplicationthatdemonstratesthedifferencesbyrunningthesetwodifferentversionsmultipletimes.We'llextractthetwotestsintomethodsandcallthemeachafewtimes:

varpbkdf2=newRfc2898DeriveBytes("password",64,256);

SingleTest(pbkdf2);

SingleTest(pbkdf2);

SingleTest(pbkdf2);

Console.WriteLine();

vartests=1000;

AvgTest(pbkdf2,tests);

AvgTest(pbkdf2,tests);

AvgTest(pbkdf2,tests);

Console.WriteLine();

Console.WriteLine("Pressanykey...");

Console.ReadKey(true);

Theoutputwilllooksomethinglikethefollowingscreenshot.Youcanfindthefullapplicationlistinginthecodethataccompaniesthisbookifyouwanttorunitforyourself:

Page 73: ASP.NET Core 1.0 High Performance

Youcanseethatthethreeindividualtestscangivewildlydifferentresultsandyettheaveragedtestsareidentical.

Tip

DetailedstepstodownloadthecodebundlearementionedinthePrefaceofthisbook.Pleasehavealook.ThecodebundleforthebookisalsohostedonGitHubathttps://github.com/PacktPublishing/ASP.NET-Core-1.0-High-Performance.Wealsohaveothercodebundlesfromourrichcatalogofbooksandvideosavailableathttps://github.com/PacktPublishing/.Checkthemout!

Yourresultswillvary.Thisisduetotheinherentvariabilityincomputersystems.EmbeddedsystemsthataretimesensitiveusuallyusearealtimeOS.Normalsoftwaresystemstypicallyrunonatime-sharingOS,whereyourinstructionscaneasilygetinterrupted,andVMsmaketheproblemevenworse.

Youwillgetdifferentresults,dependingonwhetheryoubuildindebugorreleasemodeandifyourunwithorwithoutdebugging.Releasemodewithoutdebugging(Ctrl+F5)isthefastest.

Thefollowingscreenshotshowsthesamebenchmarkingdemoapplicationrunningwithdebugging.Youcantellbecausethedotnetexecutableisshowninthetitlebarofthecommandprompt.Ifitranwithoutdebugging,thenthiswoulddisplaycmd.exe(onWindows),asinthepreviousscreenshot.

Page 74: ASP.NET Core 1.0 High Performance

Note

UnittestingisveryvaluableandyoumayevenpracticeTest-DrivenDevelopment(TDD),butyoushouldbecarefulaboutincludingperformancetestsasunittests.Unittestsmustbequicktobevaluable,andteststhataccuratelymeasurethetimetakenforoperationsareoftenslow.Youshouldsetatimeoutonyourunitteststomakesurethatyoudon'twriteslowoneswithexternaldependencies.Youcanstilltestperformance,butyoushoulddoitintheintegrationtestingstagealongwithteststhathitanAPI,DB,ordisk.

Page 75: ASP.NET Core 1.0 High Performance

ScienceWedealtwiththecomputerincomputersciencebyshowcasingsomehardwareinthepreviouschapter.Now,it'stimeforthesciencebit.

It'simportanttotakeascientificapproachifyouwishtoachieveconsistentlyreliableresults.Haveamethodologyortestplanandfollowitthesamewayeverytime,onlychangingthethingthatyouwanttomeasure.Automationcanhelpalotwiththis.

It'salsoimportanttoalwaysmeasureforyourusecaseonyoursystemswithyourdata.Whatworkedwellforsomeoneelsemaynotworkoutgreatforyou.

Wewilltalkmoreaboutscienceandstatisticslaterinthebook.Takingasimpleaveragecanbemisleadingbutit'sfinetouseitasagentleintroduction.ReadChapter8,TheDownsidesofPerformanceEnhancingTools,formoreonconceptssuchasmediansandpercentiles.

Page 76: ASP.NET Core 1.0 High Performance

RepeatabilityResultsneedtoberepeatable.Ifyougetwildlydifferentresultseverytimeyoutest,thentheycan'tbereliedupon.Youshouldrepeattestsandtaketheaverageresulttonormalizeoutanyvariabilityintheapplicationorhardwareundertest.

Itisalsoimportanttoclearlyrecordtheunitsofmeasurement.Whenyoucompareanewvaluetoahistoricone,youneedtoknowthis.NASAfamouslylostaMarsprobebecauseofunitconfusion.

Onlychangeonething

Whentesting,youaimtomeasuretheimpactofasinglechange.Ifyouchangemorethanonethingatatime,thenyoucannotbesurewhichonehasmadethedifference.

Theaimistominimizetheeffectsofanyotherchangesapartfromtheoneyouareinterestedin.Thismeanskeepingexternalfactorsasstaticaspossibleandperformingmultipletests,takingtheaverageresult.

Page 77: ASP.NET Core 1.0 High Performance

SummaryLet'ssumupwhatwecoveredaboutmeasurementinthischapterandwhatwe'llcoverinthenextchapter.Wecoveredtheimportanceofmeasurementinsolvingperformanceproblems.Withoutmeasuring,youcannothopetowritehigh-performancesoftware;youwillbecodinginthedark.

Wehighlightedsomeofthetoolsthatyoucanusetomeasureperformance.Weshowedyouhowtouseaselectionoftheseandhowtowriteyourown.

Wealsocoveredthevalueoftakingascientificapproachtomeasurement.Makingsurethatyourresultsarerepeatableandthatyourecordthecorrectunitsofmeasurementareimportantconcerns.

Inthenextchapter,wewilllearnhowtofixcommonperformanceproblems.Youwillgaintheskillstospeedupthelow-hangingfruitandmakeyourselflooklikeaperformancewizardtoyourcolleagues.Nolongerwillitbeacaseofitworkedintest,it'sanoperationsproblemnow.

Page 78: ASP.NET Core 1.0 High Performance

Chapter3.FixingCommonPerformanceProblemsThischaptergetsintothemeatofoptimization,onceyouidentifyandlocateperformanceproblems.Itcoversaselectionofthemostcommonperformanceissuesacrossavarietyofareasandexplainssimplesolutionstosomeofthemistakespeopleoftenmake.Whenusingthesetechniques,you'lllooklikeawizardtoyourclientsandcolleaguesbyquicklyspeedinguptheirsoftware.

Topicscoveredinthischapterincludethefollowing:

NetworklatencySelectN+1problemsDiskI/OissuesonvirtualmachinesAsynchronousoperationsinawebapplicationPerformingtoomanyoperationsinonewebrequestStaticsitegeneratorsPragmaticsolutionswithhardwareShrinkingoverly-largeimages

Mostoftheproblemsinthischaptercenteronwhathappenswhenyouaddlatencytocommonoperationsorwhenthroughputisreducedfromwhatitwasindevelopment.ThingsthatworkedfineintestwheneverythingwasononephysicalmachinewithminimaldataarenownolongerquiteasspeedywhenyouhaveanAPIonadifferentcontinent,afulldatabaseonadifferentmachinetoyourwebserver,anditsvirtualdisksomewhereelseonthenetworkentirely.

Youwilllearnhowtoidentifyandfixissuesthatarenotalwaysapparentwheneverythingisrunningonasinglemachine.You'llseehowtoidentifywhenyourO/RMorframeworkbehavesbadlyandistoochattywiththedatabase,whichcaneasilyhappenifit'snotusedcorrectly.

Wewillseehowtoensurethatworkisperformedinthemostappropriateplace,andwe'lllookatsomewaysofkeepingyourimagessmallusingthecorrectresolutionandformat.Thesetechniqueswillensurethatyourapplicationisefficientandthatdataisnotsentoverthewireunnecessarily.

We'llalsodiscusshowtomitigateperformanceissueswithanalternativeapproachbyimprovingtheunderlyinghardwaretoreducethefactorsthatamplifyissuesinbadsoftware.Thiscanbeagoodtemporarymeasureifthesoftwareisalreadydeployedtoproductionandinuse.Ifyoualreadyhaveliveperformanceproblemsthenthiscanbuyyousometimetoengineeraproperfix.

Page 79: ASP.NET Core 1.0 High Performance

LatencyAscoveredinpreviouschapters,latencyisthedelaythatoccursbeforeanoperationcancomplete,sometimesalsoknownaslag.Youmaynotbeabletocontrolthelatencyoftheinfrastructurethatyoursoftwarerunson,butyoucanwriteyourapplicationinsuchawaythatitcancopewiththislatencyinagracefulmanner.

Thetwomaintypesoflatencythatwewilldiscussherearenetworklatencyanddisklatency.Asthenamessuggesttheseare,respectively,thedelayinperforminganoperationoverthenetworkandthedelaytoreadfromorwritetoapersistentstoragemedium.Youwilloftendealwithbothatthesametime,forexample,adatabase(DB)querytoaserveronaremotevirtualmachinewillrequirethefollowingoperations:

AnetworkoperationfromwebservertoDBserverAnetworkoperationfromDBservertoremotediskonaStorageAreaNetwork(SAN)Adiskoperationtolookupdataonthephysicaldrive

Note

AlthoughSolidStateDrives(SSDs)havemuchlowerlatencythanspinningplatterdisks,theyarestillrelativelyslow.WhenwetalkaboutdiskI/Ohere,werefertobothtypesofdrive.

Youcanclearlyseethat,ifyouissuetoomanyDBoperations,thelatencypresentintypicalproductioninfrastructurewillcompoundtheproblem.YoucanfixthisbyminimizingthenumberofDBoperationssothattheycan'tbeamplifiedasmuch.

Let'sillustratethiswithanexample.Let'ssupposeyouwishtoreturn200recordsfromyourDBandtheroundtriplatencyis50milliseconds(ms).Ifyouretrievealloftherecordsatonce,thenthetotaltimewillbe50msplusthetimetotransfertherecords.However,ifyoufirstretrievealistoftherecordidentifiersandthenretrieveallofthemindividually,thetotaltimewillbeatleast201*50ms=10.05seconds!

Unfortunately,thisisaverycommonmistake.Inasystemwherelatencydominatesthroughput,itisimportanttokeeprequeststoaminimum.

Page 80: ASP.NET Core 1.0 High Performance

AsynchronousoperationsMostnew.NETframeworkAPIsthathavesignificantlatencywillhaveasynchronous(async)methods.Forexample,the.NETHTTPclient(supersedingthewebclient),SMTPclient,andEntityFramework(EF)allhaveasyncversionsofcommonmethods.Infact,theasyncversionisusuallythenativeimplementationandthenon-asyncmethodissimplyablockingwrappertoit.Thesemethodsareverybeneficialandyoushouldusethem.However,theymaynothavetheeffectthatyouimaginewhenappliedtowebapplicationprogramming.

Note

Wewillcoverasyncoperationsandasynchronousarchitecturelaterinthisbook.We'llalsogointoMessageQueuing(MQ)andworkerservices.Thischapterisjustaquickintroductionandwewillsimplyshowyousometoolstogoafterthelow-hangingfruitonwebapplications.

AnasyncAPIreturnscontroltothecallingmethodbeforeitcompletes.Thiscanalsobeawaitedsothatoncompletion,executionresumesfromwheretheasynchronouscallwasmade.Withanativedesktopormobileapplication,awaitinganasyncmethodreturnscontroltotheuserinterface(UI)thread,whichmeansthatthesoftwareremainsresponsivetouserinput.Theappcanprocessuserinteractionsratherthanblockingonyourmethod.Traditionally,youmayhaveusedabackgroundworkerforthesetasks.

YoushouldneverperformexpensiveworkontheUIthread.Therefore,thistechniquedoesincreaseperformancefornativeapplications.However,forawebapplicationthisUIblockingproblemdoesnotexistbecausethebrowseristheUI.Therefore,thistechniquewillnotincreaseperformanceforasingleuserinisolation.

AwaitingasynchronousAPImethodsinawebapplicationisstillgoodpractice,butitonlyallowsthesoftwaretoscalebetterandhandlemoreconcurrentusers.Awebrequesttypicallycannotcompleteuntiltheasyncoperationalsocompletes.Therefore,althoughthethreadissurrenderedbackintothethreadpoolandyoucanuseitforotherrequests,theindividualwebrequestwillnotcompletequicker.

Page 81: ASP.NET Core 1.0 High Performance

SimpleasynchronoustoolsAsthisbookdealswithwebapplicationprogramming,wewon'tgointomuchmoredetailonnativeapplicationUIsinthischapter.Instead,wewillshowcasesomesimpletoolsandtechniquesthatcanhelpwithasynctasksinwebapplications.

Thetoolsweareabouttocoveroffersomesimplesolutionsthatareonlysuitableforverysmallapplications.Theymaynotalwaysbereliable,butsometimestheycanbegoodenough.Ifyouareafteramorerobustsolution,thenyoushouldreadthelaterchaptersaboutdistributedarchitecture.

Page 82: ASP.NET Core 1.0 High Performance

BackgroundqueuingBackgroundqueuingisausefultechniquewhenyouhaveanoperationthatdoesnotneedtooccurstraightaway.Forexample,loggingstatstoadatabase,sendingane-mail,orprocessingapaymenttransaction.Ifyouperformtoomuchworkinasinglewebrequest,thenbackgroundqueuingmayofferaconvenientsolution,especiallyifyoudon'trequiretheoperationtoalwayssucceed.

IfyouuseASP.NET4.6(oranyversionfrom4.5.2onwards),thenyoucanuseHostingEnvironment.QueueBackgroundWorkItemtorunamethodinthebackground.Thisispreferabletosimplysettingataskrunning,asifASP.NETshutsdownthenitwillissueacancellationrequestandwaitforagraceperiodbeforekillingtheitem.However,thisstilldoesnotguaranteecompletionbecausetheapplicationcandieatanypointduetoanunexpectedrebootorhardwarefailure.Ifthetaskneedstocomplete,thenitshouldbetransactionalandmakearecordofsuccessuponcompletion.Itcanthenberetriedifitfailed.Queuingabackgroundworkitemisokayforfire-and-forgetevents,ifyougenuinelydon'tcarewhethertheysucceedornot.

Unfortunately,HostingEnvironment.QueueBackgroundWorkItemisnotpartofASP.NETCore.Therefore,ifyouwanttousethis,thenyouwillhavetosimplyqueueajob.Wewillshowyouhowtodothislater,butifyouusethefullversionofASP.NET,thenyoucandothefollowingtosendane-mailinthebackground:

varclient=newSmtpClient();

HostingEnvironment.QueueBackgroundWorkItem(ct=>

client.SendMailAsync(message));

Assumingthatyoualreadyhaveyourmessage,thiswillcreateanSMTPclientandsendthee-mailmessageinthebackgroundwithoutblockingfurtherexecution.Thisdoesnotusethect(cancellationtoken)variable.Keepinmindthatthee-mailisnotguaranteedtobesent.Therefore,ifyouneedtodefinitelydispatchit,thenconsiderusinganothermethod.

IfyouuseASP.NETCore,thenthisfunctionalityisnotavailable.However,youcanmanuallycreatesomethingsimilarwithTask.Runasinthefollowingexample.However,thisisprobablynotthebestapproachforanythingnontrivial:

Task.Run(()=>asyncMethod(cancellationToken));

Ifyoucancancelyourtask,thenyoucangettheApplicationStoppingtokenfromaninjectedinstanceoftheIApplicationLifetimeinterfacetopassinasyourcancellationtoken.Thiswillletyourtaskknowwhentheapplicationisabouttostop,andyoucanalsoblockshutdownwithitwhileyougracefullycleanup.

Youshouldusethistechniquewithcaution,sowewon'tgiveyouafullexamplehere.Although,youshouldnowhaveenoughpointerstodigdeeperandunderstandtheASP.NETCoreapplicationlifecycleifyouwish.

Page 83: ASP.NET Core 1.0 High Performance

HangfireHangfireisanexcellentlibrarytorunsimplebackgroundjobs.ItdoesnotsupportASP.NETCoreyet,butthisisplanned(refertoANCLAFS.comforthelatestinformation).Ifyouusethefull.NET,thenyoushouldconsideritandyoucanreadmoreathangfire.io.

Youneedpersistentstorage,suchasSQLServer,touseHangfire.Thisisrequiredsothatitcanensurethattasksarecompleted.Ifyourtasksareveryquick,thenthisoverheadcanoutweighthebenefits.Youcanreducethelatencyusingmessagequeuesorthein-memorystoreRedis,buttheseareadvancedtopics.

AsthisbookfocusesonASP.NETCoreandHangfiredoesnotsupportityet,wewon'tcoveritsuseinmoredetail.Itisalsobeyondthescopeofthischapterintermsofquickandeasysolutions.

Page 84: ASP.NET Core 1.0 High Performance

SelectN+1problemsYoumayhaveheardofSelectN+1problemsbefore.It'sanameforaclassofperformanceproblemsthatrelatetoinefficientqueryingofaDB.Thepathologicalcaseiswhereyouqueryonetableforalistofitemsandthenqueryanothertabletogetthedetailsforeachitem,oneatatime.Thisiswherethenamecomesfrom.Insteadofthesinglequeryrequired,youperformNqueries(oneforthedetailsofeachitem)andtheonequerytogetthelisttobeginwith.PerhapsabetternamewouldbeSelect1+N.

Youwillhopefullynotwritesuchbad-performingqueriesbyhand,butanO/RMcaneasilyoutputveryinefficientSQLifusedincorrectly.Youmightalsousesomesortofbusinessobjectsabstractionframework,whereeachobjectlazilyloadsitselffromtheDB.Thiscanbecomeaperformancenightmareifyouwanttoputalotoftheseobjectsinalistorcalculatesomedashboardmetricsfromalargeset.

Note

WewillgointodetailaboutSQLandO/RMoptimizationinChapter5,OptimizingI/OPerformance.Thischapterwillsimplyoffersomequickfixestocommonproblems.

Ifyouhaveaslowapplicationthathasperformanceissueswhenretrievingdata,thenSelectN+1maybetheproblem.RunaSQLprofilertool,asdescribedinthepreviouschapter,todiscoverifthisisthecase.IfyouseelotsofSQLqueriesforyourdatainsteadofjustone,thenyoucanmoveontothesolutionstage.Forexample,ifyourscreenfillswithqueriesonapageload,thenyouknowyouhaveaproblem.

Inthefollowingexample,wewillusethemicro-O/RMDapper(madebytheteamatStackOverflow)tobetterillustratewhatoccurs.However,youaremorelikelytoencountertheseproblemswhenusingalargelazyloadinglibraryorO/RM(suchasEForNHibernate).

Note

EntityFrameworkCore1.0(previouslyEF7)doesnotsupportlazyloading,soyouareunlikelytoencounterSelectN+1problemswhenusingit.PreviousversionsofEFdosupportthisanditmaybeaddedtoEFCoreinthefuture.

Youcurrentlyneedtouseabetapre-releaseversionofDappertoworkwithASP.NETCore.AswithGlimpse,thismaybestablebythetimeyoureadthis(checkANCLAFS.com).TouseGlimpsewithDapper,youneedtousetheGlimpse.ADOpackage,whichunfortunatelydoesnotyetsupport.NETCore.

Considerasimpleblogwebsite.Onthehomepage,wewouldlikealistofthepostsalongwiththenumberofcommentseachposthas.Ourblogpostmodelmaylooksomethinglikethefollowing:

Page 85: ASP.NET Core 1.0 High Performance

namespaceSelectNPlusOne.Models

{

publicclassBlogPost

{

publicintBlogPostId{get;set;}

publicstringTitle{get;set;}

publicstringContent{get;set;}

publicintCommentCount{get;set;}

}

}

Wealsohaveamodelforacomment,whichmaylooklikethis.

namespaceSelectNPlusOne.Models

{

publicclassBlogPostComment

{

publicintBlogPostCommentId{get;set;}

publicstringCommenterName{get;set;}

publicstringContent{get;set;}

}

}

Note

Asthisisanexample,wekeptthingssimpleandonlyusedasinglesetofmodels.Inarealapplication,youwilltypicallyhaveseparateviewmodelsanddataaccesslayermodels.Thecontrollerwillmapbetweenthese,perhapsassistedbyalibrary,suchasAutoMapper(automapper.org).

OurviewtorenderthisintoHTMLmaylooksomethinglikethefollowing:

@modelIEnumerable<SelectNPlusOne.Models.BlogPost>

<tableclass="table">

<tr>

<th>Title</th>

<th>#Comments</th>

</tr>

@foreach(varpostinModel)

{

<tr>

<td>@post.Title</td>

<td>@post.CommentCount</td>

</tr>

}

</table>

Wewanttopopulatethesemodelsandviewfromourdatabase.Wehavetwotables,whichlooklikethis:

Page 86: ASP.NET Core 1.0 High Performance

Therelationshipbetweenthetwotablesinquestionlookslikethefollowing:

Inourcontroller,wecanwritecode,suchasthefollowingtoquerythedatabase,populatethemodelfromthedatabaseresults,andreturntheviewtorenderit:

using(varconnection=newSqlConnection(connectionString))

{

awaitconnection.OpenAsync();

varblogPosts=awaitconnection.QueryAsync<BlogPost>(@"

SELECT*FROMBlogPost");

foreach(varpostinblogPosts)

{

varcomments=await

connection.QueryAsync<BlogPostComment>(@"

Page 87: ASP.NET Core 1.0 High Performance

SELECT*FROMBlogPostComment

WHEREBlogPostId=@BlogPostId",

new{BlogPostId=post.BlogPostId});

post.CommentCount=comments.Count();

}

returnView(blogPosts);

}

Wetestthisanditworks!Wefeelprettyhappywithourselves.Itcompletesquicklyonourlocaltestdatabasethatcontainsahandfulofrows.Weusedtheasyncmethodseverywhere,whichmustbewhatmakesthissoquick.Weevenonlygetthecommentsforeachbloginquestion,notallcommentseverytime.WealsousedaparameterizedquerytoavoidSQLinjection,andeverythinglooksgood.Shipit!

Note

Asthisisanexample,wekeptitsimpleforclarity.Inarealapplication,youwillwanttousetechniquessuchasdependencyinjection(suchastheDIbuiltintoASP.NETCore)tomakeitmoreflexible.

Unfortunately,whenthedatastartstoincrease(aspostsandcommentsareadded),theblogstartstogetmuchslowerwithpagestakingalongertimetoload.Ourreadersgetboredwaitingandgiveup.Audiencefiguresdropalongwithrevenue.

Let'sprofilethedatabasetoseewhattheproblemmightbe.WerunSQLServerProfilerfilteringonthedatabaseinquestion,andlookattheSQLbeingexecuted.

ThefollowingscreenshotshowsthefilterdialoginSQLServerProfiler:

Thetracethatwecapturerevealsthatlotsofqueriesarebeingexecuted;fartoomanyforthedatathatweneed.Theproblemisthatourcodeisnotveryefficientbecauseitusesmultiplesimple

Page 88: ASP.NET Core 1.0 High Performance

queriesratherthanoneslightlymorecomplicatedone.

Ourcodefirstgetsalistofblogpostsandthengetsthecommentsforeachpost,onepostatatime.Wealsobringbackwaymoredatathanweneed.Asyncdoesnotspeedupanindividualrequestbecausewestillneedallofthedatabeforewecanrenderthepage.

Note

ThebadcodingisobviousinthisexamplebecauseDapperhastheSQLrightinyourcode.However,ifyouuseanotherO/RM,thenyouwouldn'ttypicallyseetheSQLinVisualStudio(oryoureditorofchoice).ThisisanadditionalbenefitofusingDapperbecauseyouseetheSQLwhereit'sused,sotherearenosurprises.

However,themainbenefitofDapperisthatit'sfast,veryfast,andmuchfasterthanEF.It'sagreatchoiceforperformanceandyoucanreadmoreaboutitatgithub.com/StackExchange/dapper-dot-net.

Weonlywantacountofthecommentsforeachpostandwecangeteverythingthatweneed(andonlywhatweneed)inonequery.Let'salterourpreviouscodetouseaslightlymorecomplicatedSQLqueryratherthantwosimplerqueries,oneofwhichwasinsideaforeachloop:

Tip

ASQLqueryinsidealoopisanobviouscodesmellthatindicatesthingsmaynotbeaswellthought-outastheycanbe.

using(varconnection=newSqlConnection(connectionString))

{

awaitconnection.OpenAsync();

varblogPosts=awaitconnection.QueryAsync<BlogPost>(@"

SELECT

bp.BlogPostId,

bp.Title,

COUNT(bpc.BlogPostCommentId)'CommentCount'

FROMBlogPostbp

LEFTJOINBlogPostCommentbpc

ONbpc.BlogPostId=bp.BlogPostId

GROUPBYbp.BlogPostId,bp.Title");

returnView(blogPosts);

}

Thismoreefficientcodeonlyperformsasinglequeryagainstthedatabaseandgetsalloftheinformationthatweneed.Wejointhecommentstabletothepostsinthedatabaseandthenaggregatebygrouping.Weonlyrequestthecolumnsthatweneedandaddthecountofthecommentstoourselection.

Let'sprofilethenewcodetoseewhetherwefixedtheproblem.Thefollowingimageshowsthatwenowonlyhaveasinglequerybeingexecutedratherthanthethousandsbeingexecutedbefore:

Page 89: ASP.NET Core 1.0 High Performance

Thenumberofquerieshasbeendramaticallyreduced.Therefore,thepageloadsmuchfaster.However,thepageisstillverybigbecausealltheblogpostsarelistedonitandtherearealot.Thisslowsdownrenderingandincreasesthetimetodeliverthepagetoabrowser.

Page 90: ASP.NET Core 1.0 High Performance

EfficientpagingInarealapplication,youwanttoimplementpagingsothatyourlistisnottoolongwhenalotofdataisinthetable.It'sabadideatolistthousandsofitemsonasinglepage.

YoumaywanttodothiswithLINQcommandsbecausetheyareveryconvenient.However,youneedtobecareful.IfyourO/RMisnotLINQawareoryouaccidentallycasttothewrongtypealittletooearly,thenthefilteringmayoccurinsidetheapplicationwhenthebestplacetoperformthisfilteringisactuallyinthedatabase.Yourcodemayberetrievingallofthedataandthrowingmostofitawaywithoutyourealizingit.

Perhapsyouaretemptedtomodifytheactionmethodreturnstatementtolooksomethinglikethefollowing:

returnView(blogPosts.OrderByDescending(bp=>bp.CommentCount)

.Skip(pageSize*(pageNumber-1))

.Take(pageSize));

Thisworksandwillspeedupyourapplicationconsiderably.However,itmaynothavetheeffectthatyouthinkithas.Theapplicationisquickerbecausetheviewrenderingisspeedierduetogeneratingasmallerpage.ThisalsoreducesthetimetosendthepagetothebrowserandforthebrowsertorendertheHTML.

Yet,theapplicationstillgetsalloftheblogpostsfromthedatabaseandloadsthemintomemory.Thiscanbecomeaproblemastheamountofdatagrows.IfyouwanttouseLINQmethodssuchasthis,thenyouneedtocheckthattheyarehandledallthewaytothedatabase.It'saverygoodideatoreadthedocumentationforyourO/RMorframeworkanddouble-checktheSQLthatisgeneratedusingaprofiler.

Let'shavealookatwhattheSQLshouldlooklike.Forexample,ifyouuseSQLServer,startingwiththeprecedingquery,youcantakeonlythetoptenmost-commentedpostsbyalteringitlikethefollowing:

SELECTTOP10

bp.BlogPostId,

bp.Title,

COUNT(bpc.BlogPostCommentId)'CommentCount'

FROMBlogPostbp

LEFTJOINBlogPostCommentbpc

ONbpc.BlogPostId=bp.BlogPostId

GROUPBYbp.BlogPostId,bp.Title

ORDERBYCOUNT(bpc.BlogPostCommentId)DESC

Weorderbycommentcountindescendingorder.However,youcansortbydescendingIDtogetaroughreversechronologicalorderifyoulike.Fromthisorderedset,weselect(ortake)onlythetoptenrecords.

Page 91: ASP.NET Core 1.0 High Performance

Ifyouwanttoskiprecordsforpaging,theSELECTTOPclauseisnotgoodenough.InSQLServer2012andonward,youcanusethefollowinginstead:

SELECT

bp.BlogPostId,

bp.Title,

COUNT(bpc.BlogPostCommentId)'CommentCount'

FROMBlogPostbp

LEFTJOINBlogPostCommentbpc

ONbpc.BlogPostId=bp.BlogPostId

GROUPBYbp.BlogPostId,bp.Title

ORDERBYCOUNT(bpc.BlogPostCommentId)DESC

OFFSET0ROWS

FETCHNEXT10ROWSONLY

YoucanadjustthevalueforOFFSETtogetthecorrectentriesforyourpagenumber.TheFETCHNEXTvaluewillchangethepagesize(thenumberofentriesonapage).Youcanpassthesevaluesinwithaparameterizedquery,asfollows:

using(varconnection=newSqlConnection(connectionString))

{

awaitconnection.OpenAsync();

varblogPosts=awaitconnection.QueryAsync<BlogPost>(@"

SELECT

bp.BlogPostId,

bp.Title,

COUNT(bpc.BlogPostCommentId)'CommentCount'

FROMBlogPostbp

LEFTJOINBlogPostCommentbpc

ONbpc.BlogPostId=bp.BlogPostId

GROUPBYbp.BlogPostId,bp.Title

ORDERBYCOUNT(bpc.BlogPostCommentId)DESC

OFFSET@OffsetRowsROWS

FETCHNEXT@LimitRowsROWSONLY",new

{

OffsetRows=pageSize*(pageNumber-1),

LimitRows=pageSize

}

);

returnView(blogPosts);

}

YoucanpassinthepagesizeandnumberasURLparametersifyouupdateyouractionmethodsignaturetothefollowing:

publicasyncTask<IActionResult>Index(intpageNumber=1,

intpageSize=10)

Here,weprovideddefaultvaluesforbothparameters,sotheyareoptional.Whennoparametersareprovided,thenthefirstpageoftenresultsisshown.Weneedtomultiplythepagesizebythezero-indexedpagenumbertocalculatethecorrectoffset.Itshouldbezeroforthefirstpagesothatnorecordsareskipped.

Page 92: ASP.NET Core 1.0 High Performance

Tip

Itwouldbeaverygoodideatoapplysomevalidationtothepagingparameters.Don'tallowuserstosetthemtoanythingoutsideofareasonablerange.Thisisleftasanexercisetothereader.

Ifwelookintheprofileratthequeriesbeingexecutedonthedatabaseserver,thenwecanseewhatSQLisnowbeingrun.Wecanalsoseethetimetakenandcomparethistoourresultsfrompreviously:

Thequeryinthescreenshotgetsthedataforthethirdpagewiththepagesizesetto50entries.Therefore,itusedanoffsetof100(toskipthefirsttwopagesof50)andfetchedthenext50rows.TheURLquerystringforthiscanlooksomethinglikethefollowing:

/?pagenumber=3&pagesize=50

Page 93: ASP.NET Core 1.0 High Performance

Wecanseethatthedurationofthequeryhasdecreasedfrom24mspreviouslyto14msnow.

Tip

NotehowtheSQLexecutesdifferentlywhenparametersarepassedintothequery.Thisismuchsaferthanconcatenatinguser-suppliedvaluesdirectlyintoaSQLcommand.

Ifyoudonotuseanyparameters,thenthedefaultvaluesareusedandthehomepageshowsonlytenentries,whichlookssomethinglikethefollowingscreenshot,dependingonthedatainthedatabase:

Bydefault,thehomepageonlydisplaysthetop10mostcommentedposts,butyoucaneasilyaddpagenavigationwithhyperlinks.SimplyaddthepagenumberandpagesizequerystringparameterstotheURL.

YoucanusetheexampleURLquerystringshownpreviouslyoneitherthehomepageorthebadpagingpath,forexample,/Home/BadPaging/?pagenumber=3&pagesize=50.

Thelinksinthenavigationbarloadtheexamplesthatwejustwalkedthrough.Thebestisthe

Page 94: ASP.NET Core 1.0 High Performance

sameasthehomepageandisthedefault.Top10andbadpagingshouldbefairlyself-explanatory.Badwilltakealongtimetoload,especiallyifyouusetheDBcreationscriptincludedwiththeproject.Youcantimeitwithyourbrowserdevelopertools.

ForpreviousversionsofSQLServer(priorto2012),therearepagingworkaroundsusingROW_NUMBER()ornestedSELECTstatements,whichinvertthesortorder.Ifyouuseanotherdatabase,suchasPostgreSQL,MySQL,orSQLite,thenyoucaneasilyimplementpagingwiththeLIMITclause.ThesefreedatabasesoftenhavemorefeaturesthanSQLServer,suchastheLimitclausementionedhereandaconcatenationaggregatortonamejustoneother.

Note

OneofthetoutedbenefitsofbigO/RMsisthelayerofabstractionthattheyoffer.Thisallowsyoutochangethedatabasethatyouuse.However,inpractice,itisraretochangesomethingascoreasadatabase.Asyoucanseefromthesimplepagingexample,syntaxvariesbetweendatabasesforanythingotherthansimplestandardSQL.Togetthebestperformance,youreallyneedtounderstandthefeaturesandcustomsyntaxofthedatabasethatyouuse.

Page 95: ASP.NET Core 1.0 High Performance

StaticsitegeneratorsThedatabaseisthelogicalplacetoperformanyworktofilterandsortdata.Doingthisintheapplicationisawaste.However,forasimpleblogthatisupdatedinfrequently,adatabasemaybeunnecessaryinthefirstplace.Itmayevenbecomethebottleneckandslowthewholeblogdown.Thisisatypicalproblemofblogengines,suchasWordPress.Abetterapproachmaybetouseastaticsitegenerator.

AstaticsitegeneratorprerendersallofthepagesandsavestheresultingHTML.Thiscaneasilybeservedbyasimplewebserverandscaleswell.Whenachangeismadeandpagesneedupdating,thenthissiteisregeneratedandanewversionisdeployed.Thisapproachdoesn'tincludedynamicfeatures,suchascomments,butthird-partyservicesareavailabletoprovidetheseaddedextras.

ApopularstaticsitegeneratorisJekyll,whichiswritteninRuby.GitHubprovidesafreestaticsite-hostingservicecalledGitHubPages,whichsupportsJekyll,andyoucanreadmoreaboutitatpages.github.com.Anotherstaticsitegenerator(writteninGo)isHugo,whichyoucanreadaboutatgohugo.io.Thesetoolsarebasicallyaformofextremecaching.We'llcovercachinginthenextsectionandlateroninthisbook.

It'softenworthtakingastepbacktoseewhethertheproblemthatyou'retryingtosolveisevenaproblem.Youmaywellimprovedatabaseperformancebyremovingthedatabase.

Page 96: ASP.NET Core 1.0 High Performance

PragmaticsolutionswithhardwareThebestapproachtotakewithapoorlyperformingapplicationisusuallytofixthesoftware.However,itisgoodtobepragmaticandtrytolookatthebiggerpicture.Dependingonthesizeandscaleofanapplication,itcanbecheapertothrowbetterhardwareatit,atleastasashorttermmeasure.

Hardwareismuchcheaperthandevelopertimeandisalwaysgettingbetter.Installingsomenewhardwarecanworkasaquickfixandbuyyousometime.Youcanthenaddresstherootcausesofanyperformanceissuesinsoftwareaspartoftheongoingdevelopment.Youcanaddalittletimetothescheduletorefactorandimproveanareaofthecodebaseasyouworkonit.

Onceyoudiscoverthatthecauseofyourperformanceproblemislatency,youhavetwopossibleapproaches:

Reducethenumberoflatency-sensitiveoperationsReducethelatencyitselfusingfastercomputersorbymovingthecomputersclosertogether

Withtheriseofcloudcomputing,youmaynotneedtobuyorinstallnewhardware.Youcanjustpaymoreforahigher-performinginstanceclassoryoucanmovethingsaroundinsideyourcloudprovider'sinfrastructuretoreducelatency.

Page 97: ASP.NET Core 1.0 High Performance

AdesktopexampleToborrowanexamplefromnativedesktopapplications,itisquitecommontohavepoorly-performingLineofBusiness(LoB)applicationsoncorporatedesktops.Thedesktopwillprobablybeoldandunderpowered.Thenetworkingbacktothecentraldatabasemaybeslowbecausetheconnectionmightbeoveraremotelinktoaregionaloffice.

Withabadly-writtenapplicationthatistoochattywiththeDB,itcanbebetter,performance-wise,toruntheapplicationonaservercloseto(oronthesameserveras)theDB.PerhapstheapplicationworkspaceandDBserverscanbeinthesameserverrackatthedatacenterandconnectedbyGigabit(ortenGigabit)Ethernet.

TheusercanthenusearemotedesktopconnectionorCitrixsessiontointeractwiththeapplication.ThiswillreducethelatencytotheDBandcanspeedthingsup,eventakingintoconsiderationthelagoftheremoteUI.ThiseffectivelyturnsthedesktopPCintoathinclient,similartohowoldmainframesareused.

Forexample,youcanbuildahigh-performanceserverwithRAIDSSDsandlotsofRAMformuchlessthanthecostofthedevelopertimetofixalargeapplication.Evenbadly-writtensoftwarecanperformwellifyouruntheapplicationandDBtogetheronthesamemachine,especiallyifyourunitonbaremetalwithnovirtualmachinesintheway.Thistacticwouldbuyyoutimetofixthingsproperly.

Theseremoteapplicationandvirtualizationtechnologiesareusuallysoldastoolstoaiddeploymentandmaintenance.However,thepotentialperformancebenefitsarealsoworthconsidering.

Duetotheriseofwebapplications,thickclientdesktopapplicationsarenowlesscommon.Architectureseemstooscillatebetweencomputationontheserveranddoingworkontheclient,astherelativeprogressofnetworkingspeedandprocessingpowerraceeachother.

Page 98: ASP.NET Core 1.0 High Performance

WebapplicationsThesamerelocationapproachdoesnottypicallyworkaswellforwebapplications,butitdependsonthearchitectureused.Thegoodnewsisthat,forwebapplications,youusuallycontroltheinfrastructure.Thisisnotnormallythecasefornativeapplicationhardware.

Ifyouuseathree-tierarchitecture,thenyoucanmovetheapplicationserversclosertotheDBserver.Whetherthisiseffectiveornotdependsonhowchattythewebserversarewiththeapplicationservers.IftheyissuetoomanywebAPIrequests,thenthiswon'tworkwell.

Atwo-tierarchitecture(wherethewebserverstalkdirectlytothedatabase)ismorecommonfortypicalwebapplications.Therearesolutionsusingclustereddatabasesorread-onlymirrorstoplacethedataclosetothewebservers,buttheseaddcomplexityandcost.

Whatcanmakeasignificantdifferenceareproxyservers.ApopularopensourceproxyserverisVarnishandyoucanalsousetheNGINXwebserverasaproxy.Proxyserverscachetheoutputofwebserverssothatapagedoesn'thavetoberegeneratedforeachuser.Thisisusefulforsharedpagesbutcachingishard;typically,youshouldnotcachepersonalizedpages.Youdon'twanttoaccidentallyservesomeone'sauthenticatedprivateinformationtoanotheruser.

ProxiessuchasVarnishcanalsoroutedifferentpartsofyourwebsitetodifferentservers.IfyouhaveasmallareaofyoursitethatperformsbadlyduetoDBchatter,thenyoucouldhostthatpartfromwebserverson(orverycloseto,suchasonthesameVMhost)theDBmachinesandrouterequestsforittothere.Therestofthesitecouldremainontheexistingwebserverfarm.

Thisisn'talongtermsolution,butitallowsyoutosplitoffapoorlyperformingpartofyourprogramsothatitdoesn'timpacttherestofyoursystem.You'rethenfreetofixitonceit'sbeendecoupledorisolated.YoucanevensplitoffthedatarequiredtoaseparateDBandsynchronizeitwithabackgroundprocess.

TherearealsoContentDeliveryNetworks(CDNs),suchasCloudFlare,AmazonCloudFront,andAzureCDN,whicharegoodtocachestaticassets.CDNscachepartsofyoursiteindatacentersclosetoyourusers,reducingthelatency.CloudFlarecanevenaddHTTPStoyoursiteforfree,includingautomaticallyissuingcertificates.

Note

YoucanreadmoreabouttheCDNofferingsofCloudFlare(includingHTTP/2serverpushandWebSocketsonthefreeplan)atwww.cloudflare.com.

WewillcovercachinginmoredetailinChapter7,LearningCachingandMessageQueuing,sowewon'tgointomoredetailhere.Cachingisachallengingsubjectandneedstobeunderstoodwellsothatyoucanuseiteffectively.

Page 99: ASP.NET Core 1.0 High Performance

OversizedimagesWhilewe'reonthesubjectofstaticassets,weshouldbrieflymentionimageoptimization.We'llcoverthisinmuchmoredetailinthenextchapter,butit'sworthhighlightingsomecommonproblemshere.Asyouhaveverylittlecontrolovernetworkconditionsbetweenyourinfrastructureandtheuser,lowthroughputmaybeaprobleminadditiontohighlatency.

Webapplicationsheavilyuseimages,especiallyonlandingpagesorhomepages,wheretheymightformafullscreenbackground.Itisregrettablycommontoseearawphotofromacamerasimplydroppedstraightin.Imagesfromcamerasaretypicallymanymegabytesinsize,fartoobigforawebpage.

Youcantestwhetherthereareproblemsonawebpageusingatool,suchasGoogle'sPageSpeedInsights.Visitdevelopers.google.com/speed/pagespeed/insights,enteraURL,andclickonANALYZEtoviewtheresults.Googleusethisinformationaspartoftheirsearchengineranking,soyouwoulddowelltotakeitsadviceuptoapoint.Slowsitesranklowerinsearchresults.

Youcanalsousethebrowserdevelopertoolstoviewthesizeofimages.PressF12andlookatthenetworktabafterapageloadtoviewhowmuchdatawastransferredandhowlongittook.Youcanoftenmisstheseperformanceissuesonalocalmachineortestserverbecausetheimagewillloadquickly.Afterthefirstload,itwillalsobestoredinthebrowser'scache,somakesureyoudoafullhardreloadandemptyordisablethecache.InChrome(whenthedevtoolsareopen),youcanright-clickorlongclickonthereloadbuttonfortheseextraoptions.It'salsoagoodideatousethebuilt-inthrottlingtoolstoseehowauserwillexperiencethepageloading.

Themostbasicimageoptimizationproblemstypicallyfallintotwocategories:

ImagesthatareoverlylargeforthedisplayareatheyaredisplayedinImagesthatusethewrongcompressionformatforthesubjectmatter

Page 100: ASP.NET Core 1.0 High Performance

ImageresolutionThemostcommonissueisthatanimagehastoohigharesolutionfortheareathatdisplaysit.Thisforcesthebrowsertoresizetheimagetofitthescreenorarea.Ifthesizeofthefileisunnecessarilylarge,thenitwilltakelongertobetransferredoveraninternetconnection.Thebrowserwillthenthrowawaymostoftheinformation.Youshouldresizetheimageaheadoftimebeforeaddingittothesite.

Therearemanyimagemanipulationtoolsavailabletoresizepictures.IfyourunWindows,thenPaint.NET(www.getpaint.net)isanexcellentfreepieceofsoftware.ThisismuchbetterthanthePaintprogramthatcomeswithWindows(althoughthiswillworkifyouhavenootheroption).

Forotherplatforms,GIMP(www.gimp.org)isverygood.Ifyoupreferusingthecommandline,thenyoumaylikeImageMagick(imagemagick.org),whichcanperformlotsofimagemanipulationtasksprogrammaticallyorinbatches.Therearealsocloud-hostedimagemanagementservices,suchasCloudinary(cloudinary.com).

Youshouldshrinkimagestotheactualsizethattheywillbedisplayedontheuser'sscreen.Therecanbecomplicationswhendealingwithresponsiveimages,whichscalewiththesizeoftheuser'sscreenorbrowserwindow.AlsokeepinmindhighDPIorRetinadisplays,whichmayhavemorethanonephysicalpixeltoeverylogicalpixel.Yourimagesmayhavetobebiggertonotlookblurry,buttheupperboundisstilllikelytobelowerthantherawsize.Itisraretoneedanimageatmorethantwicethesizeofthedisplayedresolution.Wewilldiscussresponsiveimagesinmoredetaillaterinthisbook,butitisworthkeepingtheminmind.

ThefollowingimagedisplaystheresizingdialogfromPaint.NET:

Page 101: ASP.NET Core 1.0 High Performance

Whenresizinganimage,itisusuallyimportanttokeeptheaspectratiooftheimagethesame.Thismeanschangingthehorizontalandverticalsizesinproportiontoeachother.

Forexample,reducingtheHeightfrom600pxto300pxandreducingtheWidthfrom800pxto400px(meaningbothdimensionsarereducedby50%)keepstheimagelookingthesame,onlysmaller.Mostimage-manipulationsoftwarewillassistwiththisprocess.Keepingtheaspectratiothesamewillavoidimageslookingstretched.Ifimagesneedtofitadifferentshape,thentheyshouldbecroppedinstead.

Page 102: ASP.NET Core 1.0 High Performance

ImageformatThenextmostcommonproblemisusingimagesinthewrongfileformatforthecontent.Youshouldneveruserawuncompressedimages,suchasbitmap(BMP),ontheweb.

Fornaturalimagessuchasphotos,usetheJPEGfileformat.JPEGisalossycodec,whichmeansthatinformationislostwhenusingit.Itisverygoodforpictureswithalotofgradientsinthem,suchasimagesofnaturalscenesorpeople.JPEGlookspoorifthereisanytextintheimagebecausetherewillbecompressionartifactsaroundtheedgesoftheletters.Mostmid-andlow-endcamerasnativelysaveimagesasJPEG,soyoudonotloseanythingbystayingwithit.However,youshouldresizetheimagestomakethemsmaller,asmentionedpreviously.

Forartificialimagessuchasdiagramsoricons,usePNG.PNGisalosslesscodec,whichmeansthatnoinformationisdiscarded.Thisworksbestforimageswithlargeblocksofsolidcolor,suchasdiagramsdrawninpaintingsoftwareorscreenshots.Thisalsosupportstransparency,soyoucanhaveimagesthatdon'tappearrectangularoraretranslucent.YoucanalsohaveanimatedPNGs,whichareofsuperiorqualitytoGIFs,butwewon'tgointothedetailsoftheminthischapter.

Youcanaltertheformatofimagesusingthesametoolsthatyouusetoresizethem,asmentionedpreviously,bysimplychangingthefileformatwhensavingtheimage.Asalways,youshouldtestforwhatworksbestinyourspecificusecase.Youcanperformexperimentsbysavingthesameimageindifferentformats(anddifferentresolutions)thenobservingthesizesofthefilesondisk.

ThefollowingimagedisplaystheavailableimageoptionsinPaint.NET.AdditionalformatsareavailableandwewillgointomoredetailinChapter4,AddressingNetworkPerformance:

EvenwhenyouonlychoosebetweenJPEGandPNG,youcanstillmakeasignificantdifference.Thefollowingscreenshotdisplaysthedifferenceinthesizeofthefileofthesameimageintworesolutionsandtwoformats.

Page 103: ASP.NET Core 1.0 High Performance

Thefollowingtestimageistheoneusedintheexperiment.DuetothehardedgesitlooksbestasaPNG,butthegradientbackgroundmakesitmoredifficulttocompress:

Note

Thetestimagesusedhereareavailablefordownloadwiththisbook,soyoucantrytheexperimentforyourself.

Inawebcontext,thisparticularimagemaybebestservedwithatransparentbackgroundusingCSSforthegradient.However,simpleshapes,suchasthesecanbetterberepresentedasScalableVectorGraphics(SVG)orwithaHTML5canvas.

Page 104: ASP.NET Core 1.0 High Performance

SummaryInthischapter,youlearnedaboutsomecommonperformanceproblemsandhowtofixthem.Wecoveredasynchronousoperations,SelectN+1problems,pragmatichardwarechoices,andoverly-largeimages.

Inthenextchapter,wewillexpandonimageoptimizationandextendthistootherformsofcompressionfordifferenttypesofresources.We'lllookatthenewprocessforthebundlingandminificationofstaticassetsinASP.NETCoreusingopensourcetools.

Additionally,wewillintroducenetworkingtopics,suchasTCP/IP,HTTP,WebSockets,andencryption.We'llalsocovercaching,includinganotherlookatCDNs.

Page 105: ASP.NET Core 1.0 High Performance

Chapter4.AddressingNetworkPerformanceThischapterbuildsonasubsetoftheproblemsthatwerediscussedinthepreviouschapterbutinmoredetail.Itdealswithlatency,orlag,whichoriginatesatthenetworkinglevelbetweentheuserandtheapplication.Thisismostlyapplicabletowebapplicationswheretheuserinteractswiththeapplicationviaawebbrowser.Youwilllearnhowtooptimizeyourapplicationtocaterforbandwidthandlatencythatisunknownandoutsideofyourcontrol.You'llcompressyourpayloadstobeassmallaspossible,andthenyouwilldeliverthemtotheuserasquicklyaspossible.Youwilllearnaboutthetoolsandtechniquesthatcanbeusedtoachieveafastandresponsiveapplication.You'llalsoseethetrade-offsinvolvedandbeabletocalculatewhetherthesemethodsshouldbeappliedtoyoursoftware.

Thetopicsthatwewillcoverinthischapterincludethefollowing:

TCP/IPHTTPandHTTP/2HTTPS(TLS/SSL)WebSocketsandpushnotificationsCompressionBundlingandminificationCachingandCDNs

Thischapterdealswithhowtospeeduptheexperienceforauserusingyourapplication.Theskillsinthischapterarejustasapplicabletoastaticsiteorclient-sidewebappastheyaretoadynamicwebapplication.

Thesetopicsapplytoanywebapplicationframework.However,wewillfocusonhowtheyareimplementedwithASP.NET—inparticularwiththenewASP.NETCoreimplementation,andhowthisdiffersfromtheexistingfullASP.NET.

Page 106: ASP.NET Core 1.0 High Performance

InternetprotocolsIt'simportanttoknowabouthowyourHTMLandotherassetsaredeliveredfromthewebservertoyouruser'sbrowser.Muchofthisisabstractedawayandtransparenttowebdevelopment,butit'sagoodideatohaveatleastabasicunderstandinginordertoachievehighperformance.

Page 107: ASP.NET Core 1.0 High Performance

TCP/IPTransmissionControlProtocol/InternetProtocol(TCP/IP)isthenameforapairofcommunicationprotocolsthatunderpintheinternet.IPisthelower-levelprotocolofthetwo,andthisdealswithroutingpacketstotheircorrectdestinations.IPcanrunontopofmanydifferentlower-levelprotocols(suchasEthernet),andthisiswhereIPaddressescomefrom.

TCPisalayeraboveIP,anditisconcernedwiththereliabledeliveryofpacketsandflowcontrol.TCPiswhereportscomefrom,suchasport80forHTTP,andport443forHTTPS.ThereisalsotheUserDatagramProtocol(UDP),whichcanbeusedinsteadofTCP,butitprovidesfewerfeatures.

HTTPrunsontopofTCP,anditisusuallywhatyouwilldealwithinawebapplication.YoumayoccasionallyneedtodirectlyuseSimpleMailTransferProtocol(SMTP)tosende-mails,theDomainNameSystem(DNS)toresolvehostnamestoIPaddresses,orFileTransferProtocol(FTP)touploadanddownloadfiles.

ThebasicunencryptedversionsoftheseprotocolsrundirectlyonTCP,butthesecureencryptedversions(HTTPS,SMTPS,andFTPS)havealayerinbetweenthem.ThislayeriscalledTransportLayerSecurity(TLS),andthisisthemodernsuccessortotheSecureSocketsLayer(SSL).SSLisinsecureanddeprecated,anditshouldnolongerbeused.However,thetermSSLisstillcommonlyandconfusinglyusedtodescribeTLS.AllbrowsersrequiretheuseofTLSencryptiontosupportHTTP/2.

Youmaynotoftenthinkaboutthelower-levelprotocolswhenyoubuildwebapplications.Indeed,youmaynotneedtoconsiderevenHTTP/HTTPSthatmuch.However,theprotocolstackbelowyourapplicationcanhavesignificantperformanceimplications.

Thefollowingdiagramshowshowtheprotocolsaretypicallystacked:

Page 108: ASP.NET Core 1.0 High Performance

Slow-start

TCPimplementsanalgorithmcalledslow-startforcongestion-controlpurposes.Thismeansthattheconnectionfromabrowsertoawebserverisinitiallyslowandrampsupovertimetodiscovertheavailablebandwidth.Youcanalterthesettingsforthissothattherampupismoreaggressive,andconnectionsgetquickerfaster.Ifyouincreasetheinitialcongestionwindow,thenperformancecanimprove,especiallyonconnectionswithgoodbandwidthbuthighlatency,suchasmobile4Gorserversonothercontinents.

Page 109: ASP.NET Core 1.0 High Performance

Asusual,youshouldtestforyourusecaseperhapsusingWireshark,asdescribedpreviouslyinChapter2,MeasuringPerformanceBottlenecks.Therearedownsidestoalteringthiswindow,anditshouldbeconsideredcarefully.Althoughthismayspeedupwebsites,itcancausebuffersinnetworkingequipmenttofill,whichcangeneratelatencyproblemsforVoIPapplicationsandgamesifnoQualityofService(QoS)isinuseendtoend.

YoucanchangethisvalueonWindowsServer2008R2withahotfix(KB2472264)andhigher.YoucanalsoeasilyadjustthisonLinux,andASP.NETCoreenablesyoutorunyour.NETwebapponLinux(andMacOSX)inadditiontoWindows.

Wewon'tprovidedetailedinstructionsherebecausethisshouldbeacautiouslyconsidereddecision,andyoushouldn'tapplyadviceblindly.Youcaneasilyfindinstructionsonlinefortheoperatingsystemthatyouuseonyourwebserver.

TCPslow-startisjustoneexampleofwhyyoucan'tignorethelowerlevelsofInternettechnologyontheshouldersofwhichwebapplicationsstand.Let'smoveupthestackalittletotheapplicationlayer.

Page 110: ASP.NET Core 1.0 High Performance

HTTPAsawebapplicationdeveloperwhowantstodeliverhighperformance,it'simportanttounderstandHypertextTransferProtocol.YoushouldknowwhatversionofHTTPyouuse,howitworks,andhowthisaffectsthings,suchasrequestpipeliningandencryption.

HTTP/1.1istheversionthatyouwillprobablybemostfamiliarwithtodaybecauseithasbeeninuseforsometime.HTTP/2isbecomingmorepopular,anditchangesthebestwaytodomanythings.

Headers

HTTPusesheaderstoprovidemetadataaboutarequestalongwiththemainpayloadinthebodyofthemessage,muchlikee-mailsdo.Youwon'tseetheseheaderswhenyouviewthesource,butyoucanobservethemusingthebrowserdevelopertools.Youcanuseheadersformanythings,suchascachecontrolandauthentication.Cookiesarealsosentandreceivedasheaders.

BrowserswillonlyopenalimitednumberofHTTP/1.1connectionsatonetimetoasinglehost.Ifyourequirealotofrequeststoretrievealltheassetsforapage,thentheyarequeued,whichincreasesthetotaltimetakentofullyloadit.WhencombinedwiththeTCPslow-startmentionedpreviously,thiseffectcanbeamplified,degradingtheperformance.ThisislessofaproblemwithHTTP/2,whichwewillcovershortly.Youcanreducetheimpactofthisproblembyallowingthebrowsertoreuseconnections.Youcandothisbyensuringthatyourwebserverdoesn'tsendaConnection:closeheaderwithHTTPresponses.

HTTPmethods

Therearemultiplemethods(orverbs)thatHTTPuses.ThemostcommonareGETandPOST,buttherearemanymore.Typically,weuseGETrequeststoretrievedatafromaserver,andweusePOSTtosubmitdataandmakechanges.GETshouldnotbeusedtoalterdata.

OtherusefulverbsareHEADandOPTIONS.HEADcanchecktheheadersforaGETrequestwithouttheoverheadofdownloadingthebody.Thisisusefultocheckcachingheaderstoseewhethertheresourcehaschanged.OPTIONSiscommonlyusedforCrossOriginResourceSharing(CORS)toperformapreflightchecktovalidateadomain.

OtheroftenusedverbsarePUT,DELETE,andPATCH.WemainlyusetheseforRepresentationalStateTransfer(REST)APIsbecausetheycanmimicoperationsonresourcesorfiles.However,notallsoftware(suchassomeproxyservers)understandsthem,sosometimes,weemulatethemusingPOST.YoumayevenhaveproblemswithOPTIONSbeingblockedbyproxiesandwebservers.

Statuscodes

HTTPusesnumericresponsecodestoindicateastatus.Youareprobablyfamiliarwith200(OK)and404(NotFound),buttherearemanyothers.Forexample,451indicatesthatthecontenthas

Page 111: ASP.NET Core 1.0 High Performance

beenblockedbyagovernment-mandatedcensorshipfilter.

Note

The451statuscodeisinreferencetothebookFahrenheit451(whosetitleisthepurportedtemperatureatwhichpaperburns).Youcanreadtheofficialdocument(RFC7725)attools.ietf.org/html/rfc7725.Ifthiscodeisnotused,thenitcanbetrickytodiscoverifandwhyasiteisunavailable.Forexample,youcanfindoutwhethertheUKgovernmentisblockingyoursiteatblocked.org.uk,butthisisjustavolunteereffortrunbytheOpenRightsGrouptheBritishversionoftheElectronicFrontierFoundation(EFF).

Wecommonlyuse3xxcodesforredirection(perhapstoHTTPS).Therearevariousformsofredirectionwithdifferentperformancecharacteristics(andothereffects).Youcanusea302totemporarilyredirectapage,butthenthebrowserhastorequesttheoriginalpageeverytimetoseewhethertheredirecthasended.ItalsohasbadimplicationsforSearchEngineOptimization(SEO),butwewon'tdiscussthesehere.

Abetterapproachistousea301toindicateapermanentredirect.However,youneedtobecareful,asthiscan'tbeundoneandclientswon'tlookattheoriginalURLagain.IfyouuseredirectstoupgradeusersfromHTTPtoHTTPS,thenyoushouldalsoconsiderusingHTTPStrictTransportSecurity(HSTS)headers.Again,dothiscarefully.

Encryption

HTTPencryptionisveryimportant.Itnotonlysecuresdataintransittopreventeavesdropping,butitalsoprovidesauthentication.Thisensuresthatusersactuallyconnecttothesitethattheythinktheyareandthatthepagewasn'ttamperedwith.Otherwise,unscrupulousinternetconnectionproviderscaninjectorreplaceadvertsonyoursite,ortheycanblockinternetaccessuntilyouhaveoptedoutofaparentalfilter.Or,thesecanbeworsethings,suchasstealingyouruser'sdata,whichyouareusuallyrequiredbylawtoprotect.

Thereisreallynogoodreasontodaytonotuseencryptioneverywhere.Theoverheadsaretiny,althoughwewillstillconsiderthemandshowyouhowtoavoidpotentialissues.ArgumentsagainstusingHTTPSareusuallyhangoversfromatimelongagowhencomputationwasexpensive.

Moderncomputinghardwareisverycapableandoftenhasspecialaccelerationforcommonencryptiontasks.Therearemanystudiesthatshowthattheprocessingoverheadsofencryptionarenegligible.However,therecanbeasmalldelayininitiallysettingupasecureconnectionforthefirsttime.Inordertounderstandthis,itisusefultoillustrateasimplemodelofhowTLSworks.

Therearetwopartstosecurecommunication:theinitialkeyexchangeandtheongoingencryptionofthechannel.Sessionciphers,suchastheAdvancedEncryptionStandard(AES),canbeveryquick,andtheycanoperateatclosetolinespeed.However,theseciphersaresymmetricalandbothpartiesneedtoknowthekey.Thiskeyneedstobedistributedsecurelysothatonlythetwo

Page 112: ASP.NET Core 1.0 High Performance

communicatingpartiespossessit.Thisiscalledkeyexchange,anditusesasymmetricencryption.Thisusuallyalsorequiresathirdpartytovouchfortheserver,sowehaveasystemofcertificates.Thisinitialsetupistheslowpart,althoughwewillshowyouanalternativefordevicesthatlacktheAESaccelerationlater.

Keyexchange

Asmentionedpreviously,keyexchangeistheprocessofsecurelysharinganencryptionkeybetweentwopartieswithoutbeingintercepted.Therearevariousmethodsofdoingthis,whichmostlyrelyonasymmetricencryption.Unlikesymmetricencryption(thatweexchangethiskeyfor),thiscanonlybeperformedinonedirectionwithasinglekey.Inotherwords,thekeythatisusedtoencryptcannotbeusedtodecrypt,andadifferentkeyisrequired.Thisisnotthecaseforthemajorityofthedataoncewehavesharedakey.Thereasonthatwedothisisthatsymmetricencryptionisfasterthanasymmetricencryption.Therefore,itisnotusedforeverythingandisonlyneededtoencryptanotherkey.

Inadditiontoexchangingakey,thebrowser(orotherHTTPSclient)shouldcheckthecertificatetoensurethattheserverbelongstothedomainthatitclaimsto.Someprogrammaticclientsfailtodothisbydefault,sothisisworthcheckingout.Youcanalsoimplementcertificatepinning(eveninthebrowserwithHTTPPublicKeyPinning)toimprovesecurity,butthisisbeyondthescopeofthisbook.

Wewillillustratetwovariationsofkeyexchangebyanalogyinsimplifiedformstoshowyouhowtheprocessworks.Youcanlookupthetechnicaldetailsifyouwish.

RSA

RSAistraditionallythemostcommonkey-exchangemechanismthatisusedforTLS.Untilrecently,weuseditonmostHTTPSconnections.

RSAstandsforRivest-Shamir-Adlemanafterthenamesofitscreators,anditisprobablythemostpopularformofpublickeycryptography.TheBritishsnoopingagency,GovernmentCommunicationsHeadquarters(GCHQ),supposedlyconceivedpublickeycryptographyataroundthesametime,butasitwasonlymadepublicin1997,it'simpossibletoprovethis.TheinventioncreditgoestoWhitfieldDiffieandMartinHellman,whorecentlypickedupaTuringAwardforit.We'lltalkmoreabouttheirworkshortly.

Note

TheTuringAwardistheNobelPrizeofcomputing.It'snamedafterAlanTuring,thelegendarycomputingpioneerwhohelpedtheallieswinWWIIwhileworkingforthenascentGCHQ,butwhowaslaterbetrayedbytheBritishgovernment.

RSAuseslargeprimenumberstogenerateapublicandprivatekeypair.Thepublickeycanbeusedtoencryptinformationthatcanonlybedecryptedwiththeprivatekey.Inadditiontothis,theprivatekeycanbeusedtosigninformation(usuallyahashofit),whichcanbeverifiedwiththe

Page 113: ASP.NET Core 1.0 High Performance

publickey.RSAisoftenusedtosignTLScertificatesevenifanotheralgorithmisusedasthekeyexchangemechanism(thisisnegotiatedduringtheinitialTLShandshake).

Tip

ThishashingandsigningofcertificatesiswhereyoumayhaveheardofSHA-1certificatesbeingdeprecatedbybrowsers.SHA-1isnolongerconsideredsecureforhashingand,likeMD5beforeit,shouldnotbeused.CertificatechainsmustnowuseatleastanSHA-2hashingalgorithm(suchasSHA-256)tosign.

AnanalogytohelpexplainhowRSAworksistothinkofsendingalockinsteadofsendingakey.Youcanpostanopenpadlocktosomeone,retainingthekeytoit.Theycanthenuseyourlocktosecureacasewithakeyoftheirsinsideandsenditbacktoyou.Now,onlyyoucanopenthecasetogetthenewkey.

Inreality,thisismorecomplicated.Youcan'tbesurethatsomeonedidn'tinterceptyourlockandthenusetheirownlocktogetthekeyandcopyitbeforesendingitontoyou.Typically,wesolvethiswithPublicKeyInfrastructure(PKI).Atrustedthirdpartywillsignyourcertificateandverifythatitisindeedyourpublickeyandthatyouownthelock.BrowserstypicallydisplayawarningifaCertificateAuthority(CA)doesnotcountersignthecertificateinthisway.

Diffie-Hellman(D-H)keyexchangeisanothermethodofgainingasharedkey.InventedshortlybeforeRSA,ithasonlyrecentlybecomepopularontheweb.Thisispartlyduetothereducedcomputationalcostoftheellipticcurvevariant.However,anotherreasonisthattheephemeralversionsprovideaqualitycalledPerfectForwardSecrecy(PFS).UnlikeRSA,thesessionkeyforthesymmetricencryptionneverneedstobetransmitted.Bothpartiescancalculatethesharedkeywithoutitneedingtobesentonthewire(eveninanencryptedstate)orpermanentlystored.Thismeansthataneavesdroppedencryptedexchangecannotbedecryptedinthefutureifthekeyswererecovered.WithRSAkeyexchange,youcanrecoverarecordedcommunicationinplaintextifyouobtaintheprivatekeyslater.PFSaisusefulcountermeasureagainstmasssurveillance,whereallcommunicationiscaughtinadragnetandpermanentlystored.

D-Hisbetterexplainedwithacolormixinganalogy,wherepaintsrepresentnumbers.Thetwopartieschooseasharedcolor,andeachpartychoosesasecretcoloroftheirown.Bothmixthesharedcolorwiththeirsecretcolorandsendtheresulttotheother.Eachpartythenmixesthecolorthattheyreceivedwiththeirsecretcoloragain.Bothpartiesnowhavethesamecolorwithouteverhavingtosendthiscoloranywherewhereitcouldbeobserved.

Asthisisnotabookaboutsecurity,wewon'tgointoanymoredetailonencryptionalgorithms.Ifyouareinterested,thereisahugeamountofinformationavailablethatwecan'tcoverhere.Encryptionisalargesubject,butsecurityisanevenbroaderconcern.

TLShandshake

ThepointofbrieflyexplaininghowTLSkeyexchangeworksforvariousmethodsistoshowthat

Page 114: ASP.NET Core 1.0 High Performance

itiscomplex.Manymessagesneedtobesentbackandforthtoestablishasecureconnection,andnomatterhowfasttheconnection,latencyslowsdowneverymessage.ThisalloccursintheTLShandshake,wheretheclient(usuallyawebbrowser)andservernegotiatecommoncapabilitiesandagreeonwhatcipherstheyshoulduse.ThereisalsoServerNameIndication(SNI)toconsider,whichissimilartotheHTTPhostheaderinthatitallowsmultiplesitestousethesameIPaddress.Someolderclientsdon'tsupportSNI.

WecanobservetheTLShandshakeusingWireshark.Wewon'tgointoahugeamountofdetail,butyoucanseethatatleastfourmessagesareexchangedbetweentheclientandserver.Theseareclienthello,serverhello(includingthecertificateandserverkeyexchange),clientkeyexchange,andcipheragreement.Thebrowsermaysendmoremessagesifwedonotoptimallyconfiguredthings,suchasrequestinganintermediatecertificate.Thismayalsocheckarevocationlisttoseewhetherthecertificatewasrevoked.

ThefollowingscreenshotshowsaTLShandshakecapturedwithWireshark:

Allthesenetworkoperationshappenquickly.However,iftheconnectionhasahighlatency,thentheseextramessagescanhaveanamplifiedeffectonperformance.Thecomputationaldelaysaretypicallymuchsmallerthanthenetworkdelays,sowecandiscountthese,unlessyouuseveryoldhardware.Fortunately,therearesomesimplethingsyoucandothatwillhelpspeedthingsupandletyouenjoyhighperformancewhilestillbeingsecure.

Delaydiagnostics

TherearevariousmechanismsthatarebuiltintoTLSthatcanyoucanusetospeeditup.However,therearealsothingsthatwillslowitdownifyoudon'tdothemcorrectly.SomegreatfreeonlinetoolstoassessyourTLSconfigurationareavailablefromQualysSSLLabsatssllabs.com.Theservertestatssllabs.com/ssltestisveryuseful.YouenteraURL,andtheygiveyouagradealongwithlotsofotherinformation.

Forexample,ifweanalyzethepacktpub.comsite,wecanseethatonthedateofthetestitgotaBgrade.ThisisduetosupportingweakDiffie-HellmanparametersandtheobsoleteandinsecureRC4cipher.However,itisnotalwaysassimpleasremovingoldciphers.Youcanhaveaverysecuresite,butyoumightexcludesomeofyourcustomers,whouseolderclientsthatdon'tsupportthelateststandards.Thiswill,ofcourse,varydependingonthenatureofyourclientbase,andyoushouldmeasureyourtrafficandconsideryouroptionscarefully.

Page 115: ASP.NET Core 1.0 High Performance

ThefollowingscreenshotshowssomeofthereportfromSSLLabsforpacktpub.com.

Ifwehavealookatasitewithabetterconfiguration(emoncms.org),wecanseethatitgetsanAgrade.YoucangetanA+gradeusingHSTSheaders.Additionally,theseheadersavoidtheoverheadofaredirect.Youmayalsobeabletogetyoursiteembeddedinapreloadedlistshippedwithbrowsersifyousubmitthedomainstothevendors.

Page 116: ASP.NET Core 1.0 High Performance

ThefollowingscreenshotshowssomeofthereportfromSSLLabsforemoncms.org:

TheoptionschosenbymodernbrowserswouldtypicallybeanEllipticCurveDiffie-HellmanEphemeralkeyexchange(ECDHE)withanRSASHA-256signatureandAESsessioncipher.TheephemeralkeysprovidePFSbecausetheyareonlyheldinmemoryforthesession.Youcanseewhatconnectionhasbeennegotiatedbylookinginyourbrowser.

InFirefox,youcandothisbyclickingonthelockiconintheURLbarandthenclickingonthe

Page 117: ASP.NET Core 1.0 High Performance

MoreInformationbutton,asshowninthefollowingimage:

IntheTechnicalDetailssection,youwillseetheciphersuiteused.ThefollowingimagefromFirefoxshowsECDHEkeyexchangeandRSAcertificatesigning:

YoucanalsoviewthecertificatedetailsbyclickingontheViewCertificatebutton.ThedomainisusuallyincludedastheCommonName(CN)intheSubjectfield.AlternativedomainscanalsobeincludedundertheCertificateSubjectAltNameextension:

Page 118: ASP.NET Core 1.0 High Performance

InChrome,youcanlookattheTLSconnectioninformationintheSecuritytabofthedevelopertools.Forexample,thefollowingimagedisplaysthesecuritydetailsforhuxley.unop.uk:

Thefollowingscreenshotdisplaysthesamewindowforemoncms.org:

Page 119: ASP.NET Core 1.0 High Performance

Tip

YoumayneedtorefreshthepagetoseeTLSinformationifthesitewasalreadyloadedwhenyouopenedthedevelopertools.YoucanaccessthesametabbyclickingonthepadlockintheChromeURLbarandthenclickingontheDetailslink.

Youcanviewthecertificate(inthenativeoperatingsystemcertificatestore)byclickingontheOpenfullcertificatedetailsbutton.AlinkwiththesamefunctionexistsontheequivalentscreenofChromeforAndroid,althoughthecertificateinformationisreduced.

Performancetweaks

WealreadydiscussedthemostimportantperformancetweakforTLSbecauseitisnotaboutTLS.YoushouldensurethatyourHTTPconnectionsarereusable,becauseifthisisnotthecase,thenyouwillincurtheaddedpenaltyoftheTLSnegotiationalongwiththeTCPoverhead.Cachingisalsoveryimportant,andwewilltalkmoreaboutthislater.

Note

TLSandHTTPbothsupportcompression,butthesehavesecurityimplications.Therefore,considerthemcarefully.Theycanleakinformation,andadeterminedadversarycanuseananalysisofthemtorecoverencrypteddata.TLScompressionisdeprecated,anditwillberemovedinTLS1.3.Therefore,donotuseit.WewilldiscussHTTPcompressionlateroninthis

Page 120: ASP.NET Core 1.0 High Performance

chapter.

InregardtospecificadviceforTLS,thereareafewthings,whichyoucandotoimproveperformance.Themaintechniqueistoensurethatyouusesessionresumption.ThisisdifferenttoreusingHTTPconnections,andthismeansthatclientscanreuseanexistingTLSconnectionwithouthavingtogothroughthewholekeyexchange.

Tip

YoucanimplementsessionswithIDsontheserverorwithencryptedtickets(inasimilarmannertoASP.NETcookiesthatareencryptedwiththemachinekey).TherewasabugintheMicrosoftclientimplementationaroundticketencryptionkeyrotation,buttheKB3109853patchfixedit.Makesurethatyouinstallthisupdate,especiallyifyouseeexceptionsthrownwhenconnectingtosecureendpointsfromyour.NETcode.

Itisimportanttonotoverdothingsandbiggerisnotalwaysbetter,especiallywhenitcomestokeysize.Itisatrade-offbetweenperformanceandsecurity,andthiswilldependonyourspecificsituation.Ingeneral,agoodbalanceisnotusing256bitAESkeyswhen128bitwilldo.

A2048bitRSAkeyisbigenough,lowerisinsecureandlargeristooslow.YoucanusetheEllipticCurveDigitalSignatureAlgorithm(ECDSA)tosigninsteadofRSA,asitismuchquicker.However,supportislimited,soyouwouldneedtodeployRSAinparallel.

IfyouuseECDSA,thena256bitkeyissufficient.ForECDHE,256bitisalsofine,andfortheslowerversionwithoutellipticcurves(DHE),2048bitissufficient.IfyouuseECDSA,thenyouwillseethislistedinsteadoftheRSAsigningintheconnectiondetails.Forexample,whenvisitinghuxley.unop.uk,thedetailsinthefollowingscreenshotsaredisplayedinFirefox.ThisdifferenceisalsodisplayedinthepreviousChromescreenshots:

Additionally,itisimportanttoincludethefullcertificatechainwithyourcertificate.Ifyoufailtoincludeallintermediatecertificates,thenthebrowserwillneedtodownloadthemuntilitfindsoneinitstrustedrootstore.YoucanalsouseatechniquecalledOnlineCertificateStatusProtocol(OCSP)stapling,byembeddingrevocationdatasobrowsersdon'tneedtocheckacertificaterevocationlist.

Bothofthesecertificatetechniquesmayincreasethesizeofpayloads,whichcanbeanissueifbandwidthisaconcern.However,theywillreducethenumberofmessages,whichwillincreaseperformanceiflatencyisthemainproblem,whichisusuallythecase.Keepingkeysizessmallalsohelpsalittlewithbandwidth.Itishardtorecommendonegenericapproach.Therefore,asalways,testforyouruniquesituation.

Page 121: ASP.NET Core 1.0 High Performance

ThereisalsoanalternativestreamciphercalledChaCha/Poly,whichisespeciallyusefulformobiledevices.ThisusestheChaCha20streamcipherandthePoly1305MessageAuthenticationCode(MAC)algorithmtocreateasecurealternativetoRC4.AESisablockcipherandisfastwithhardwaresupport,butmanymobiledevicesandsomeoldercomputersdon'thavethisacceleration.ChaCha/Polyisfasterwhenusingjustsoftware.Therefore,thisisbetterforbatterylife.ThisissupportedinChrome,includingChromeforAndroid,andinFirefox(fromversion47).

Note

Asallalgorithmsaredifferent,youcan'tdirectlycomparekeysizesasameasureofhowsecuretheyare.Forexample,a256bitECDHEkeyisequivalenttoa3072bitRSAkey.AESisverysecurewithrelativelysmallkeys,butyoucannotuseitforkeyexchange.ChaCha/PolyismorecomparabletothesecurityofAES256thanAES128.

InthefollowingscreenshotofChromeonAndroid,youcanseethatwhenconnectingtohuxley.unop.uk,ChromeusesCHACHA20_POLY1305asthestreamcipher,ECDHEforthekeyexchange,andECDSAforthesignature:

Page 122: ASP.NET Core 1.0 High Performance

Note

Page 123: ASP.NET Core 1.0 High Performance

ThenewversionofTLS(1.3)isstilladraft,butitmaybefinalizedsoon.ItlookslikeitwillonlyallowAuthenticatedEncryptionwithAdditionalData(AEAD)ciphers.AES-GCMandChaCha/Polyaretheonlytwociphersthatcurrentlymeetthesecriteria.Itwillalsoremovesomeotherobsoletefeatures,suchasTLScompression.

ItmaysometimessoundlikeusingTLSisnotalwaysworthit,butitisanexcellentideatouseHTTPSonyourentiresite,includinganythird-partyresourcesthatyouloadin.Bydoingthis,youwillbeabletotakeadvantageoftheperformanceenhancingfeaturesofHTTP/2,whichincludetechniquesthatmeanthatitisnolongercrucialtoserveresources(suchasJavaScriptlibraries)frommultipledomains.YoucansecurelyhosteverythingyourselfandavoidtheDNS,TCP,andTLSoverheadofadditionalrequests.AllofthiscanalsobefreebecauseLet'sEncryptandCloudFlareprovidecertificatesatzerocost.Let'slookatHTTP/2indetailnow.

HTTP/2

Asthenamesuggests,HTTP/2isthenewversionofHTTP.Itcontainssomesignificantperformanceimprovementsforthemodernweb.ItwaspredatedbySPDY,whichhassincebeendeprecatedinfavorofHTTP/2.

Asmentionedpreviously,thefirststeptowardusingHTTP/2istouseHTTPSonyourentiresite.Althoughnottechnicallyrequired,mostclients(allthemajorbrowsers)mandatetheuseofTLStoenableHTTP/2.ThisismainlyduetotheApplication-LayerProtocolNegotiation(ALPN)thatTLSprovides,whichallowseasysupportforHTTP/2.Italsostopsproxyserversfrommessingupthedata,whichmanyISPsusetoreducetheircostsandrecordwhattheircustomersdoonline.

HTTP/2improvesperformanceinanumberofways.Itusescompressionevenfortheheaders,andmultiplexing,whichallowsmultiplerequeststosharethesameconnection.Italsoallowstheservertopushresourcesthatitknowstheclientwillneedbeforetheclienthasrealizeditneedsthem.Although,thisrequiressomeconfigurationtosetthecorrectheadersanditcanwastebandwidthifitisoverused.

Multiplexinghasimplicationsforbundlingandimageconcatenation(sprites),whichwewilltalkaboutinthecompressionsectionlateroninthischapter.Thisalsomeansthatyoudon'tneedtosplitassetsovermultipledomains(shards),wheretheextraoverheadsmayevenslowthingsdown.However,youmaystillwishtouseacookie-freesubdomaintoservestaticassetswithoutcookies,eventhoughthenewheadercompressionmeansthatthebandwidthsavingswillbesmaller.Ifyouuseanakeddomain(withoutawww),thenyoumayneedanewdomainnameforcookie-lessuse.

YoucanidentifywhatversionofHTTPisusedtodeliveryourassetsusingthebrowserdevelopertools.InFirefox,youcanseethisonthedetailspanelofthenetworktab.YouwillseetheversionlistedasHTTP/1.1whentheoldprotocolisinuse.

Thefollowingscreenshotshowsthatpacktpub.comusesHTTP/1.1:

Page 124: ASP.NET Core 1.0 High Performance

Tip

InChrome,youcanright-clickonthecolumnheadersinthenetworkinspectorandaddaProtocolcolumn.Youcanalsoseemoredetailednetworkinformationbyenteringchrome://net-internalsintotheaddressbar.Thisdisplaysthings,suchassessionsforHTTP/2andQuickUDPInternetConnections(QUIC)—anexperimentalmultiplexedstreamtransport.

Thefollowingscreenshotshowsthatemoncms.orgalsousesHTTP/1.1,eventhoughTLSisconfigureddifferently.TheencryptedtransportlayeristransparenttoHTTP:

WhenHTTP/2isused,youwillseetheversionlistedasHTTP/2.0.Thefollowingscreenshotdisplaysthisforhuxley.unop.uk,anditalsodisplaysCORS,caching,andcontentcompressionheaders:

Page 125: ASP.NET Core 1.0 High Performance

WebSockets

WebSocketsisadifferentprotocoltoHTTP.However,HTTPinitiatesitanditusesthesameports,sowe'lldiscussitbrieflyhere.ThisHTML5featureisusefulforpushnotificationsandRealTimeCommunication(RTC)applications.WebSocketsusethews://andwss://protocolprefixesinsteadofhttp://andhttps://.OnceestablishedbyanexistingHTTPconnection,theprotocolisfull-duplexandbinaryincontrasttoHTTP/1.

BeforeWebSockets,ifyourwebserverwantedtonotifyaclientofachange,thenyouwouldhavetouseatechnique,suchaslongpolling.Thisiswhereawebrequestisheldopenbytheserverincaseitwantstosendsomething.Whentherequestgetsaresponseorittimes-out,itisre-established.Needlesstosay,pollingisneververyefficient.

Pushnotificationscanimproveperformancefromauser'spointofviewbecausetheyreceiveupdatesassoonastheyoccur.Theydon'tneedtorefreshanythingorkeepchecking.Youcanimmediatelyrespondtotheuserwhenalongrunningprocessstarts,runitasynchronously,andnotifythemimmediatelyuponitscompletion.

Socket.IOisapopularWebSocketlibraryforNode.js.Toseeitinaction,youcanlookinthebrowserdevelopertoolsonasitethatusesit.Forexample,ifyouopenthedevtoolsandgotohttps://www.opentraintimes.com/maps/signalling/staines,youwillseetheconnectionbeingupgradedfromHTTPStoWSS(orfromHTTPtoWSifyouusetheinsecureversion).

WebSocketspredateHTTP/2,buttheyarestillrelevantdespitethenewserverpushtechnology.Thesetwofeaturesappearsimilar,buttheyservedifferentpurposes.WebSocketsareforreal-timeandtwo-waydatatransfers,andserverpushiscurrentlyjusttopreload.

Note

InadditiontoHTTP/2serverpushpreloading,thereisanewbrowserfeaturethatiscurrentlysupportedinAndroid,Chrome,andOpera,whichallowsyoutodeclareresourcepreloadinginmarkupusingrel="preload"onalinktag.Youcanreadthespecatw3c.github.io/preloadandcheckthecurrentstateofbrowsersupportatcaniuse.com/#feat=link-rel-preload.

InChrome,theprotocolswitchwilllooksomethinglikethefollowingscreenshot.Youcan'tseethecontentsofaWebSocketconnection,soyouwon'tbeabletoviewthedatabeingtransferredfromwithinthedevtools:

Page 126: ASP.NET Core 1.0 High Performance

ThereisaMicrosoftlibraryforASP.NET,whichiscalledSignalR.ThislibraryallowsyoutoperformpushnotificationswithWebSockets.Italsofallsbacktolongpollingiftheclientorserverdoesnotsupportthem.YouwillneedafairlyrecentversionofWindowsServer(2012orlater)andIIS(8.0andabove)touseWebSockets.

Unfortunately,thelateststableversion(SignalR2)doesnotsupport.NETCore.Thenewversion(SignalR3)isnotplannedforreleaseuntilaftertheReleasetomanufacturing(RTM)ofASP.NETCore,butthisisatoppriority.Youcantryabetaversion,butitmaybestablebythetimeyoureadthis.

Tip

YoumayalsowishtolookatStackExchange.NetGainasaWebSocketserver.

Page 127: ASP.NET Core 1.0 High Performance

CompressionDatacompressionisabroadtopic,andwecan'thopetocoveritall.Here,wewilllearnaboutlosslesscompressionandhowtouseitinHTTP.Wewillalsocoverlossyimagecompressionofpictureslaterinthechapter.Compressionisimportantbecauseifwecanmakefilessmaller,wecanshortenthetimethatittakestotransferthemoveranetwork.

Page 128: ASP.NET Core 1.0 High Performance

LosslesscompressionalgorithmsYoumayhavenoticedHTTPheadersfromsomeofthepreviousscreenshotswererelatedtoencoding.ThemostcommoncompressionalgorithmsforHTTParegzipandDEFLATE,whichareverysimilar.ThesearebothrelatedtothealgorithmusedinZIPfiles.IfyoudonotalreadyuseHTTPcompression,thenthisisaquickwin,anditwillimprovetheperformanceofyoursiteifyouenableit.

Therearemanyothermoreadvancedcompressionalgorithms,suchasxz,whichissimilartothe7-Zip(7z)formatandusestheLempel-Ziv-MarkovchainAlgorithm(LZMA/LZMA2).However,therearecurrentlyonlytwoadditionalalgorithmsincommonuseinmajorbrowsers.TheseareBrotliandSharedDictionaryCompressionforHTTP(SDCH).BotharefromGoogle,butonlyChromesupportsSDCH,anditrequiresalargedictionary.

Brotliismoreinteresting,andOperaandChrome(currentlybehindachrome://flags/#enable-brotliflag),andFirefoxbydefault(version44orhigher)supportit.BothbrowsersrequiretheuseofHTTPStosupportBrotli(yetanothergoodreasontouseTLS),andtheencodingtokenusedintheheadersisbr.Brotlipromisessignificantperformanceimprovements,especiallyformobiledevicesonslowconnections.

IfyouaccessasiteoverHTTP,youwillseethefollowingfortherequestheadersintheChromedevtoolsnetworkinspectorinthedetailsofarequest:

Accept-Encoding:gzip,deflate,sdch

However,ifyouuseHTTPSthenyouwillseethisinstead(afterenablingtheflag):

Accept-Encoding:gzip,deflate,sdch,br

TheservercanthenrespondwithBrotli-encodedcontentusingthisresponseheader:

Content-Encoding:br

Forexample,ifyouvisithttps://www.bayden.com/test/brotliimg.aspxinasupportedbrowser,thenBrotliwilldeliverthecontent(animageofastar).Hereisasubset(forclarityandbrevity)oftherequestheadersfromChrome:

GET/test/brotliimg.aspxHTTP/1.1

Host:www.bayden.com

Connection:keep-alive

Accept-Encoding:gzip,deflate,sdch,br

Thisisasubsetofthecorrespondingresponseheaders:

HTTP/1.1200OK

Content-Type:image/png

Content-Encoding:br

Server:Microsoft-IIS/7.5

X-AspNet-Version:4.0.30319

Page 129: ASP.NET Core 1.0 High Performance

YourAcceptEncoding:gzip,deflate,sdch,br

Fiddler(theawesomeHTTPdebuggingproxybyEricLawrencethatwementionedpreviously)alsosupportsBrotliwithasimpleadd-on(drophttps://bayden.com/dl/Brotli.exeintofiddler2\toolsandrestartit).Youcanusethistoeasilytesttheimpactonyoursitewithoutdeployinganythingtoyourwebservers.

Page 130: ASP.NET Core 1.0 High Performance

BundlingandminificationBundlingandminificationaretechniquesthatyoumayalreadybefamiliarwith.Theyspeedupthedeliveryofstaticassets.Theyareusuallyusedfortextfiles,suchasJavaScriptandCSScontent.

Bundling

Bundlingisthetechniqueofcombiningorconcatenatingmultiplefilestogethersothattheycanbedeliveredasone.ThisisagoodideawhenusingHTTP/1.1becausethenumberofconcurrentconnectionsislimited.However,bundlingislessnecessarywithHTTP/2,andinfact,itcanreduceperformance.ThenewmultiplexinginHTTP/2meansthatthereisnolongeralargepenaltywhenyourequestmanyfilesinsteadofonethatcontainallofthesamecontent.Youcantakeadvantageofthisbyonlydeliveringwhatisneededforapageratherthantheentireclientsidecodebaseforeverypage.Evenifyouselectivelybundleperpage,thiscouldbeinefficient.

Forexample,youmayincludeavalidationlibraryforusewithforms.However,becausethisisbundled,itwillbesenttoallpages,includingtheoneswithnoformstovalidate.Ifyouhaveaseparatebundleforvalidatedpages,thentheremaybeduplicationinthecommoncorecodethatisalsosent.Bykeepingthingsseparated,theclientcancachethemindividuallyandreusecomponents.Thisalsomeansthatifyouchangesomething,youonlyneedtoinvalidatethecacheofthisonepart.Theclientcankeepusingtheotherunmodifiedpartsandnothavetoredownloadthem.

Asalways,youshouldmeasureforyourparticularusecase.Youmayfindthatbundlingstillreducesthetotalfilesize.TheoverheadsforHTTP/2aremuchlowerbutstillnotzero,andcompressioncanworkbetteronlargerfiles.However,keepinmindtheimplicationsforcachingandreusability.

Minification

Minificationistheprocessofreducingthefilesizeofatextualstaticasset.Wedothisbyvariousmeans,includingstrippingoutcomments,removingwhitespace,andshorteningvariablenames.Itcanalsobeusefultoobfuscatecodetomakeithardertoreverseengineer.MinificationisstillusefulwhenyouuseHTTP/2,butyoushouldbecarefulwhentestingtocomparepreminifiedandpostminifiedfilessizeafterthelosslesscompressionhasalsobeenapplied.

Asdiscussedpreviously,youshoulduseHTTPcontentcompressionwithatleastthegziporDEFLATEalgorithms.Theseareprettyefficient;so,youmayfindthatwhencompressed,yourminifiedfileisnotmuchsmallerthanthecompressedrawsourcefile.

ChangesinASP.NETCore

Inthefull.NETFrameworkandpreviousversionsofMVC,therewasanintegratedbundlingandminificationsystem.ThishaschangedforASP.NETCore,andtherearenewtoolstoperformthiswork.

Page 131: ASP.NET Core 1.0 High Performance

Thenewtoolsthatwereadoptedincludethetaskrunnergulp,althoughyoucanuseGruntifyoupreferto.Also,ageneratortoolcalledYeomanisusedforscaffolding.Therearenowpackagemanagers,suchasBowerandnpm,whicharesimilartoNuGet,butforfrontendlibraries.Forexample,NuGetnolongerdeliversjQueryandTwitterBootstrap,andtheyuseBowerinsteadbydefault.

MostofthesetoolsarewritteninJavaScript,andtheyrunonNode.js.ThepackagemanagerforNode.jsisnpm.Thesetoolsarepopularinotheropensourcewebframeworks,andtheyarewellestablished.They'renotnewtothescene,onlynewto.NET.

Gulppackagescomefromnpmandareresponsiblefortheminificationofyourstaticassets.Thisisnowdoneatbuildtime,asopposedtorequesttime,aswaspreviouslythecase.Itworksmuchmorelikeastaticsitegeneratorthanadynamicwebapplication.Agulpfile(gulpfile.js)intherootofyourprojectconfiguresthesetasksusingJavaScript.

ThenewtoolingisnotonlyrestrictedtoASP.NETCore,andyoucanusethesefeatureswithtraditionalASP.NETapplicationsinVisualStudio.Thisisagoodexampleofthecross-pollinationandbenefitsthatthenewframeworkscanprovidetotheexistingones.

Page 132: ASP.NET Core 1.0 High Performance

ImageoptimizationDigitalmediacompressionismuchmorecomplicatedthanthelosslessfilecompressionthatwetalkedaboutpreviouslyevenifwejuststicktoimages.WebrieflymentionedwhentousePNGandwhentouseJPEGinthepreviouschapter.Here,we'llgointomuchmoredetailandexploresomeotherexoticoptions.

Wecoveredtheruleofthumb,whichsaysthatPNGisthebestimageformatforiconsandJPEGisbetterforphotos.Thesetwoformatsarethemostcommonforlosslessandlossyimagecompression,respectively.

Wewilltalkmoreaboutotherimageformatslater,butyouareusuallyconstrainedtothepopularformatsbywhatbrowserssupport.So,howcanyougetmoreoutofthecommonchoices?

PNG

PortableNetworkGraphics(PNG)isalosslessimagecompressionformatthatinternallyworkssimilarlytoaZIPfile(usingtheDEFLATEalgorithm).It'sagoodchoiceforimagesthatcontainsolidblocksofcolor,andithasabetterquality(withmorecolors)thantheoldGraphicsInterchangeFormat(GIF).

PNGsupportstransparencyinallmodernbrowsers,soyoushoulduseitinsteadofGIFforstaticimages.ThisisnotaproblemunlessyouneedtosupportInternetExplorer6,inwhichcasethisisprobablytheleastofyourtroubles.PNGalsosupportsanimationwithAnimatedPNG(APNG)files.ThesearelikeanimatedGIFsbutofamuchhigherquality.Unfortunately,onlyFirefoxandSafarisupportAPNGs.

Tip

Agreatsitetolookupwhichbrowserssupportaparticularfeatureiscaniuse.com.Youcansearchforfeaturesupport,thencheckthisagainsttheuseragentanalyticsofyoursite.Forexample,youcouldsearchforPNG-alpha,Brotli,orAPNG.

SomeZIPalgorithmimplementationsarebetterthanothers,andtheyproducesmallerfilesthatcanstillbedecodedbyeveryone.Forexample,7-ZipismuchmoreefficientthanmostotherzipcompressionsoftwareonWindows,evenwhenusingtheZIPformat,notitsnative7zformat.Likewise,youcancompressaPNGmorecompactlywithoutlosinganydataandstillhaveitworkinallbrowsers.Thisusuallycomeswithahigherupfrontcomputationalcost.However,ifyoucompressstaticassets,whichrarelychange,thenitcanbewellworththeeffort.

YoumayalreadyusethePNGOUTtooltolosslesslyreducethesizeofyourPNGimages.Ifyou'renot,thenyouprobablyshould.Youcanreadmoreaboutitanddownloaditatadvsys.net/ken/utils.htm.

However,thereisanewalgorithmcalledZopflithatoffersbettercompression,butitisveryslowtocompress.Decompressionisjustasquick,soit'sonlyasingleoptimizationcostfor

Page 133: ASP.NET Core 1.0 High Performance

precompiledresources.ZopfliisaprecursortoBrotli,butit'scompatiblewithDEFLATEandgzip,asit'snotanewformat.

YoucangetZopflifromgithub.com/google/zopfli,butyoushouldalwaystestwithyourimagesandverifythatthereisindeedafilesizereduction.Youwillfindthatthesetoolscanhelpyoudeliveryourassetsquickerandachievehigherperformance.

Youmayalsousethepracticeofcombiningmanyspritesintooneimage.Aswithbundling,thisislessnecessarywhenusingHTTP/2.However,thesamecaveatsapplyaswithcompression,andyoushouldalwaystestforyoursetofimages.

JPEG

JPEGisalossyimagecompressionformat,whichmeansthatitusuallydiscardsdatafromthepicturetomakeitsmaller.Itisbestsuitedtonaturalgradientsandcontinuoustones,suchasthosefoundinphotographs.JPEGdoesnotsupporttransparencylikePNGdoes,soifyouwanttouseoneondifferentbackgrounds,thenyouwillneedtoprerenderthem.

Tip

It'sagoodspacesavingideatoremovetheExchangeableimagefileformat(Exif)metadatafromyourJPEGfilesfortheweb.Thiscontainsinformationaboutthecamerausedandgeographicdataofwherethephotowastaken.

JPEGhasaqualitysetting,whichaffectstheimagefilesizeandthelevelofdetail.Thelowerthequality,thesmallerthefile,buttheworseitwilllook.Youcanperformtestsonyourimagestoseewhatsettingsprovideanacceptabletrade-off.Crucially,thebestvalueforthisqualitysettingwillvaryperimage,dependingonthecontent.Therearetoolsthatallowyoutoautomaticallydetecttheoptimalqualitylevel,suchasGoogle'sbutteraugli.

ThereisaninterestingprojectfromMozilla(themakersoftheFirefoxbrowser)calledmozjpeg.ThisaimstobettercompressJPEGimagesandissimilartowhatPNGOUTandZopflidoforPNGimages.YoucanusemozjpegtocompressyourJPEGimagestoasmallersizethannormal,withoutaffectingdecompressionorquality.Itisavailableatgithub.com/mozilla/mozjpeg,butyouwillneedtocompileityourself.Asalways,resultsmayvary,sotestitforthephotosonyoursite.

JPEGArchive(github.com/danielgtaylor/jpeg-archive)isahandytoolthatusesmozjpegtocompressJPEGimages,usingvariouscomparisonmetrics.Anothersimilartoolisimgmin(github.com/rflynn/imgmin),whichisslightlyolder.

Otherimageformats

Manyotherimageformatsareavailable,butyouareusuallylimitedonthewebbywhatbrowserssupport.Asdiscussedinthepreviouschapter,youshouldn'tscaleimagesinthebrowser,oryouwillgetpoorperformance.Thisusuallymeanshavingtosavemultipleseparatecopiesofsmaller

Page 134: ASP.NET Core 1.0 High Performance

images,forexample,whendisplayingthumbnails.Clearlythisresultsinduplication,whichisinefficient.Someofthesenewimageformatshavecleversolutionstotheproblemofresponsiveandscalableimages.

BPGisanimageformatbythetalentedFabriceBellard,andyoucanreadmoreaboutitatbellard.org/bpg.IthasaJavaScriptpolyfilltosupportbrowsersbeforenativesupportisaddedtoanyofthem.

WebPisanimageformatfromGoogle,andonlyChrome,Android,andOperasupportit.IthasimpressivespacesavingsoverJPEG,anditwillbeagoodchoiceifitbecomesmorewidelysupported,socheckcaniuse.comforthelatestadoptionstats.

JPEG2000isanimprovedversionofJPEG,althoughitmaybeencumberedbysoftwarepatents,soithasn'tseenwidespreadadoptionoutsideofmedicalimaging.OnlySafarisupportsJPEG2000,andthereisalsoJPEGXR,whichisonlysupportedinIE.

WhereasJPEGusesaDiscreteCosineTransform(DCT),JPEG2000isbasedonaWaveletTransform.Oneofthepropertiesthisprovidesisaprogressivedownload.Thismeansthattheimageisstoredinsuchawaythatifyoudownloadasmallpartfromthebeginningofthefile,thenyouhaveasmallerandlowerqualityversionofthefullimage.Thishasobviousapplicationsforresponsiveandscalableimages.Thebrowserwouldonlyneedtodownloadenoughoftheimagetofilltheareaitisrenderingto,andthefileneedonlybestoredonce.Noresizingandnoduplicationforthumbnailswouldberequired.ThistechniqueisalsousedintheFreeLosslessImageFormat(FLIF).

FLIFisoneofthemoreexcitingupcomingimageformats,asitisprogressiveandresponsive,butfreeandnotpatented.FLIFisstillindevelopment,butitpromisestobeveryusefulifbrowserssupportit,andyoucanreadmoreaboutitatflif.info.

Note

JPEGandPNGcansupportprogressivedownload,butthisisn'tnormallyusefulforresponsiveimages.ProgressiveJPEGsubjectivelyloadsmoregracefullyandcanevenmakefilessmaller,butinterlacedPNGusuallymakesfilesbigger.

Theproblemisthatmostoftheseprogressiveimageformatsarenotyetreadyforthemainstreambecauseallofthemajorbrowsersdonotsupportthem.It'sagoodideatokeepaneyeonthefuture,butfornow,weneedtoresizeimagesforhighperformance.

Resizingimages

Untilnewimageformatsgainwidespreadadoption,resizingisstillrequired,andyoumayneedtodothisdynamicallyfordifferentdevices.Perhaps,youalsohaveuser-submittedimagecontent,althoughyouneedtobeverycarefulwiththisfromasecuritypointofview.Someimagelibrariesarenotsafe,andaspecially-craftedimagecanexploityoursystem.Infact,manyimage-processinglibrarieshaveissueswhentheyareusedinawebcontext.

Page 135: ASP.NET Core 1.0 High Performance

Ifyouarenotextremelydiligentandcareful,thenyoucaneasilyendupwithmemoryleaks,whichcantakedownyourwebserver.Itisalwaysagoodideatoseparateandsandboxaprocessthatdealswithlargemediafiles.

Comingfroma.NETstandpoint,itcanbetemptingtouseWinFormsSystem.DrawingoritsWPFsuccessor(System.Windows.Media).However,theseweredesignedfordesktopsoftware,andMicrosoftstronglyrecommendsagainstusingtheminaserviceorwebapplication.MicrosoftrecommedstheWindowsImagingComponent(WIC),butthisisaComponentObjectModel(COM)APIthatismeantforusefromCorC++apps.Inadditiontothis,noneoftheseimaginglibrariesarecross-platform,sotheyarenotsuitableforusein.NETCore.

IfyouuseWindows,thenyoucouldtryusingImageResizerbyImazen(imazen.io),fromimageresizing.net.WhileitstillusestheGDI+System.Drawing,itisprettybattlehardened,somostofthebugsshouldhavebeenworkedout.There'salsoDynamicImage,whichwrapsthenewerWPFimagefunctionsandusesshaders.Youcanreadmoreaboutitatdynamicimage.apphb.com,althoughithasn'tbeenupdatedinawhile,anditdoesn'tsupport.NETCore.

ApopularoptioninopensourcecirclesisImageMagick,whichwe'vementionedpreviously,andaforkcalledGraphicsMagick,whichclaimstobemoreefficient.AnotherpopularimagelibraryisLibGD,andit'ssuitableforserveruse.Youcanreadmoreatlibgd.github.io.Althoughit'swritteninC,therearewrappersforotherprogramminglanguages,forexample,DotnetGDtargeting.NETCore.

Oneofthefeaturesthat.NETCorelacksisthatthereisnotyetacompellingoptionforimageprocessing.ImageResizer5mayhelpwiththiswhenreleased,soitisworthkeepinganeyeonit.Nativecodesupportisnowmuchbetterin.NETCore,asitwasapaintodoinclassic.NET,whichmayhelpwithintegratingnativecross-platformimaginglibraries.

Thereisalsoanewcross-platformversionoftheopensourceImageProcessorlibraries(imageprocessor.org),calledImageProcessorCore,whichshowspromise.However,thisisstillaworkinprogress,anditisnotyetstable.Ifyouwanttotryitout,thenyoucangetthenightlypackagesfromMyGetorbuilditfromsource.

Note

Platformsupportandcompatibilitychangesrapidly,socheckANCLAFS.comforthelatestinformation.Feelfreetocontributetothislistortotheprojects.

Fornow,itmaybeeasiertoinstallanopensourceservice,suchasThumbor,oruseacloud-basedimagingservice,suchasImageEngine(WURFL.io)orCloudinary,whichwe'vealreadymentioned.Imagemanipulationisacommontask,anditiseffectivelyasolvedproblem.Itmaybebettertouseanexistingsolutionandnotreinventthewheel,unlessit'spartofyourcorebusinessoryouhaveveryunusualrequirements.

Tip

Page 136: ASP.NET Core 1.0 High Performance

Onceyouhaveyourresizedimages,youcanloadthemresponsivelywiththepictureandsourcetagsusingthesrcsetandsizesattributes.Youcanalsousethistechniquetoprovidenewerimageformats(suchasWebP),withafallbackforbrowsersthatdon'tyetsupportthem.OryoucanuseClientHints(refertohttpwg.org/http-extensions/client-hints.htmlandcaniuse.com/#feat=client-hints-dpr-width-viewport).

Page 137: ASP.NET Core 1.0 High Performance

CachingItisoftensaid(originallybyPhilKarlton)thatcachingisoneofthehardestproblemsincomputerscience,alongwithnamingthings.Thismaywellbeanexaggeration,butcachingiscertainlydifficult.Itcanalsobeveryfrustratingtodebugifyouarenotmethodicalandpreciseinyourapproach.

Cachingcanapplyatvariousdifferentlevelsfromthebrowsertotheserverusingmanydiversetechnologies.Yourarelyusejustasinglecacheevenifyoudon'trealizeit.Multiplecachesdon'talwaysworkwelltogether,andit'svexingifyoucan'tclearone.

Webrieflytoucheduponcachinginthepreviouschapter,andwe'llgointomuchmoredetailinChapter7,LearningCachingandMessageQueuing.However,ascachinghasanimpactonnetworkperformance,we'llcoverithereaswell.

Page 138: ASP.NET Core 1.0 High Performance

BrowserAlotofcachinghappensinthewebbrowser,whichisinconvenientbecauseasyoudon'thavedirectcontroloverit(unlessit'syourbrowser).Askinguserstocleartheircacheisunsatisfactoryandconfusingtomany.Yet,youcanexertinfluenceonhowbrowserscacheresourcesbycarefullycontrollingtheHTTPheadersthatyousetandtheURLsthatyouuse.

Ifyoufailtodeclarewhatresourcesarecacheableandforhowlong,thenmanybrowserswilljustguessthis.Theheuristicsforthiscanbewildlydifferentbetweenimplementations.Therefore,thiswillresultinsuboptimalperformance.Youshouldbeexplicitandalwaysdeclarecacheinformationeven(andespecially)forassetsthatshouldn'tbecachedbymarkingthemasnoncacheable.

Tip

Youneedtobevigilantwithwhatyouadvertiseascacheablebecauseifyouarecareless,thenyoucangetyourselfintoasituationwhereyou'reunabletoupdatearesource.Youshouldhaveacache-bustingstrategyinplace,andtested,beforeusingcaching.

Therearevarioustechnologiesthatareusedaretocacheinbrowsers.ManydifferentHTTPheaderscanbeset,suchasAge,Cache-Control,ETag(EntityTag),Expires,andLast-Modified.Thesecomefromafewdifferentstandards,andtheinteractionscanbecomplex,ortheyvarybetweenbrowsers.WewillexplaintheseinmoredetailinChapter7,LearningCachingandMessageQueuing.

AnothertechniqueistouseauniqueURLforcontent.IfaURLchanges,thenabrowserwilltreatitasadifferentresource,butifitisthesame,thenitmayloaditfromitslocalcache.Someframeworkscalculateahashofthefilecontents,andthentheyusethisasaquerystringparameter.Thisway,whenthecontentsofthefilechanges,sodoestheURL.

Thereareotherandmoremodernfeaturesthatyoucanusetocache,suchastheHTML5ApplicationCache(orAppCache).Thiswasdesignedforofflinewebapplicationsandwasn'tveryflexible.Bustingthecachewascomplicatedtoputitmildly.AppCacheisalreadydeprecated,andyoushoulduseServiceWorkersinstead.Theseprovidemuchmoreflexibility,althoughsupportisprettyrecent.

Therearemanyimprovementscoming,inthelatestbrowsersthatgiveyoumorecontrol,andwe'llalsoshowyouhowtousetheminChapter7,LearningCachingandMessageQueuing.

Page 139: ASP.NET Core 1.0 High Performance

ServerThewebserverisagreatplacetocachebecauseitisusuallyunderyourcompletecontrol.However,it'snotreallypartofnetworkperformance,apartfromgeneratingthecorrectheaders.Therecanbeothergreatperformancebenefitswithserver-sidecachingintermsofimprovingthespeedtogeneratepages,butwewillcovertheseinlaterchapters.

Ifyouusethetraditional.NETFrameworkonMicrosoft'sInternetInformationServices(IIS)webserver,thenyoucanuseoutputcachingfromwithinyourapplication.Thiswilltakecareofsettingthecorrectheadersandsending304(NotModified)responsestobrowserrequests.Itwillalsocachetheoutputontheserverinmemory,ondiskorusingMemcached/Redis.Youcanaddattributestoyourcontrolleractionmethodstocontrolthecachingoptions,butotherwaysofdoingthisareavailable,forexample,intheconfigurationfiles.

OutputCacheisnotavailableinASP.NETCore,butyoucanuseResponseCachetosetthecorrectheaders.Theoutputisnotcachedontheserver,butyoucaninstallacachingproxyinfrontofit.Again,wewillcoverthismoreanddemonstrateserver-sidecachinginChapter7,LearningCachingandMessageQueuing.

IfyouwanttodisablecachingonanASP.NETCorepage,thenaddthisannotationtoyourcontrolleraction:

[ResponseCache(NoStore=true,Duration=0)]

ThiswillsetthefollowingheaderontheHTTPresponseandensurethatitisnotcached:

Cache-Control:no-store

Tocacheapageforanhour,addthefollowinginstead,Durationisinseconds:

[ResponseCache(Duration=3600,VaryByHeader="Accept")]

Thecachecontrolheaderwillthenlooklikethefollowing:

Cache-Control:public,max-age=3600

There'splentymoretosayaboutothercachingconfigurationoptionsandprofiles.Therefore,ifyou'reinterested,thenreadthelaterchapters.It'sacomplextopic,andwe'veonlyscratchedthesurfacehere.

Note

YoucanreaddocumentationaboutresponsecachinginASP.NETCoreatdocs.asp.net/en/latest/performance/caching/response.html.

Thesecachingdirectivesnotonlyinstructthebrowser,buttheyalsoinstructanyproxiesontheway.Someofthesemaybeinyourinfrastructureifyouhaveacachingproxy,suchasSquid,

Page 140: ASP.NET Core 1.0 High Performance

Varnish,orHAProxy.Orperhaps,youhaveaTLS-terminatingloadbalancer(suchasAzureApplicationGateway)toreducetheloadonyourwebserversthatalsocaches.Youcanforciblyflushthecachesofserversthatyoucontrol,buttheremaybeothercachesinbetweenyouandyouruserswhereyoucan'tdothis.

Page 141: ASP.NET Core 1.0 High Performance

ProxyserversbetweenyouandyourusersTherecanbemanyproxyserversbetweenyouandyourusersoverwhichyouhavenodirectcontrol.Theymayignoreyourcachingrequests,blockpartsofyoursite,orevenmodifyyourcontent.ThewaytosolvetheseproblemsistouseTLS,aswehavealreadydiscussed.TLScreatesasecuretunnelsothattheconnectionbetweenyourinfrastructureandthebrowsercan'teasilybetamperedwith.

CorporateproxiescommonlyManintheMiddleattack(MitM)yourconnectiontotheusersothattheycanspyonwhatemployeesaredoingonline.Thisinvolvesinstallingacustom-trustedrootcertificateonusers'workstationssothatyourcertificatecanbefaked.Unfortunately,thereisn'tmuchyoucandoaboutthis,apartfromeducatingusers.Certificatepinningiseffectiveinnativeapps,butit'snotsousefulforwebapplications.HTTPPublicKeyPinning(HPKP)isavailablebut,asitisaTrustonFirstUse(TOFU)technique,theinitialconnectioncouldbeintercepted.Clientcertificatesareanotheroption,buttheycanbedifficulttodistribute,andtheyaren'tcommonlyused.

MitMcanbeusefulifyoutrustthethirdpartyandremainincontrol.ThisisusedbysomeContentDeliveryNetworks(CDNs)tospeedupyoursite.

CDNs

CDNscanimprovetheperformanceofyoursitebystoringcopiesofyourcontentatlocationsclosertoyourusers.Services,suchastheonesprovidedbyCloudFlare,performaMitMonyourconnectionandsavecopiesatdatacentersaroundtheworld.Thedifferencefromanunauthorizedproxyisthatyoucontroltheconfiguration,andyoucanpurgethecachewheneveryoulike.

Youshouldbecarefulbecauseifyoudon'tusethecachingfeatures,thenthiscanreducetheresponsivenessofyoursiteduetotheextrahopsinvolved.MakesurethatyoumonitortheresponsetimeswithandwithoutaCDN,andyouneedafallbackplanincasetheygodown.

AnothercommonusecaseforCDNsistodistributepopularlibraries,forexample,thejQueryJavaScriptlibrary.TherearefreeCDNsfromjQuery(MaxCDN),Google,Microsoft,andcdnjs(CloudFlare)thatdothis.Thehypothesisisthatausermayalreadyhavethelibraryfromoneoftheseintheircache.However,youshouldbeextremelycarefulthatyoutrusttheproviderandconnection.Whenyouloadathird-partyscriptintoyoursite,youareeffectivelygivingthemfullcontroloveritoratleastrelyingonthemtoalwaysbeavailable.

IfyouchoosetouseaCDN,thenensurethatitusesHTTPStoavoidtamperingwithscripts.Youshoulduseexplicithttps://URLsonyoursecurepagesoratleastprotocolagnosticURLS(//),andneverhttp://.Otherwise,youwillgetmixedcontentwarnings,whichsomebrowsersdisplayastotallyunencryptedorevenblock.

YouwillneedafallbackthatishostedonyourownserversanywayincasetheCDNgoesdown.IfyouuseHTTP/2,thenyoumayfindthatthereisnoadvantagetousingaCDN.Obviously,

Page 142: ASP.NET Core 1.0 High Performance

alwaystestforyoursituation.

TherearesomeusefulnewfeaturesinASP.NETCoreviewstoeasilyenablelocalfallbackforCDNresources.We'llshowyouhowtousethemandotherfeaturesinlaterchapters.

Page 143: ASP.NET Core 1.0 High Performance

SummaryInthischapter,youlearnedhowtoimproveperformanceatthenetworklevelbetweentheedgeofyourinfrastructureandyourusers.Younowknowmoreabouttheinternetprotocolsunderyourapplicationandhowtooptimizeyouruseofthemforbesteffect.

Youlearnedhowtotakeadvantageofcompressiontoshrinktextandimagefiles.Thiswillreducebandwidthandspeedupdeliveryofassets.Wealsohighlightedcaching,andyoushouldnowseehowimportantitis.We'llcovercachingmoreinChapter7,LearningCachingandMessageQueuing.

Inthenextchapter,youwilllearnhowtooptimizetheperformanceinsideyourinfrastructure.YouwillseehowtodealwithI/Olatency,andhowtowritewell-performingSQL.

Page 144: ASP.NET Core 1.0 High Performance

Chapter5.OptimizingI/OPerformanceThischapteraddressesissuesthatoftenoccurwhenyoutakeyourfunctionallytestedapplicationandsplititupintopartsfordeployment.Yourwebservershostthefrontendcode,yourdatabaseissomewhereelseinthedatacenter,youmayhaveaStorageAreaNetwork(SAN)forcentralizedfiles,anappserverforAPIs,andthevirtualdisksareallondifferentmachinesaswell.

Thesechangesaddsignificantlatencytomanycommonoperationsandyourapplicationnowbecomessuperslow,probablybecauseit'stoochattyoverthenetwork.Inthischapter,youwilllearnhowtofixtheseissuesbybatchingqueriestogether,andperformingworkonthebestserverforthejob.Evenifeverythingrunsononemachine,theskillsthatyou'lllearnherewillhelptoimproveperformancebyincreasingefficiency.

Thetopicscoveredinthischapterincludethefollowing:

TheoperationsthatcanbeslowSelectN+1problemsindetailReturningonlywhatyouneedWritinghigh-performanceSQL

Youwilllearnabouttheoperationsthatyoushouldn'tusesynchronously,andhowtoqueryforgettingonlythedatathatyouneedinanefficientmanner.You'llalsoseehowtotameyourO/RM,andlearntowritehigh-performanceSQLwithDapper.

WebrieflycoveredsomeofthesetopicsinChapter3,FixingCommonPerformanceProblems,butherewe'lldiveintogreaterdetail.Thefirsthalfofthischapterwillfocusonbackgroundknowledgeandusingdiagnostictools,whilethesecondhalfwillshowyousolutionstoissuesyoumaycomeacross.You'llalsolearnaboutsomemoreunusualproblems,andhowtofixoralleviatethem.

We'llinitiallyfocusonunderstandingtheissues,becauseifyoudon'tappreciatetherootcauseofaproblem,thenitcanbedifficulttofix.Youshouldn'tblindlyapplyadvicethatyouread,andexpectittoworksuccessfully.Diagnosingaproblemisnormallythehardpart,andoncethisisachieved,itisusuallyeasytofixit.

Page 145: ASP.NET Core 1.0 High Performance

Input/outputI/Oisageneralnameforanyoperationinwhichyourcodeinteractswiththeoutsideworld.TherearemanythingsthatcountasI/O,andtherecanbeplentyofI/Othatisinternaltoyoursoftware,especiallyifyourapplicationhasadistributedarchitecture.

Note

Therecentriseinpopularityofthe.ioTopLevelDomain(TLD)canbepartlyattributedtostandingforI/O,butthatisnotitsrealmeaning.AsisthecaseforsomeotherTLDs,itisactuallyacountrycode.Otherexamplesinclude.lyforLibyaand.tvforTuvalu(which,liketheneighboringKiribati,maysoonbesubmergedbeneaththePacificOceanduetoclimatechange).

TheTLD.ioisintendedfortheBritishIndianOceanTerritory(BIOT),acollectionoftinybutstrategicislandswithashamefulhistory.The.ioTLDisthereforecontrolledbyaUK-basedregistry.BIOTisnothingmorethanamilitarybase,andalsohappenstobeahopontheproposedAWEfiberopticcablebetweenAustraliaandDjibouti.

Inthischapter,wewillfocusonimprovingthespeedofI/O,notonavoidingit.Therefore,wewon'tcovercachinghere.BothI/Ooptimizingandcachingarepowerfultechniquesontheirown,andwhenthey'recombined,youcanachieveimpressiveperformance.SeeChapter7,LearningCachingandMessageQueuingformoreoncaching.

Page 146: ASP.NET Core 1.0 High Performance

CategoriesofI/OThefirstchallengeistoidentifytheoperationsthattriggerI/O.Ageneralruleofthumbin.NETisthatifamethodhasanasynchronousAPI(MethodAsync()variants),thenitisdeclaringthatitcanbeslow,andmaybedoingI/Owork.Let'stakeacloserlookatsomeofthedifferentkindsofI/O.

Disks

ThefirsttypeofI/Owewillcoverisreadingfrom,andwritingto,persistentstorage.ThiswillusuallybesomesortofadiskdrivesuchasaspinningplatterHardDiskDrive(HDD),orasismorecommonthesedays,aflashmemory-basedSolidStateDrive(SSD).

HDDsareslowerthanSSDsforrandomreadsandwrites,butarecompetitiveforlargeblocktransfers.ThereasonforthisisthatthearmontheHDDhastophysicallymovetheheadtothecorrectlocationonthemagneticplatterbeforeitcanbeginthereadorwriteoperations.Ifthediskispowereddown,thenitcantakeevenlonger,astheplatterswillhavetoSpin-upfromastationarypositiontothecorrectrevolutionsperminute(rpm)beforehand.

Note

Youmayhaveheardtheterm"Spin-up"inreferencetoprovisioningagenericresource.Thishistoricallycomesfromthetimetakentospintheplattersonarotatingdiskuptotheoperationalspeed.Thetermisstillcommonlyused,eventhoughthesedaystheremaynotbeanymechanicalcomponentspresent.

Terminologylikethisoftenhasahistoricalexplanation.Asanotherexample,afloppydiskiconisnormallyusedtorepresentthesavefunction.Yetfloppydisksarenolongerinuse,andmanyyoungerusersmayneverhaveencounteredone.

Knowingwhattypeofdriveyourcodeisrunningonisimportant.HDDsperformbadlyifyoumakelotsofsmallreadsandwrites.Theyprefertohavebatchedoperations,sowritingonelargefileisbetterthanmanysmallerones.

Theperformanceofdisksissimilartothatofanetwork,inthatthereisbothlatencyandthroughput,oftencalledbandwidthinnetworkingparlance.ThelatencyofanHDDishigh,asittakesarelativelylongtimetogetstarted,butoncestarted,thethroughputcanberespectable.Youcanreaddatarapidlyifit'sallinoneplaceonthedisk,butitwillbeslowerifitisspreadallover,evenifthetotaldataisless.Forexample,copyingasinglelargefiledisk-to-diskisquick,buttryingtolaunchmanyprogramssimultaneouslyisslow.

SSDsexperiencefeweroftheseproblemsastheyhavelowerlatency,butitisstillbeneficialtokeeprandomwritestoaminimum.SSDsarebasedonflashmemory(similartothechipsusedinmemorycardsforphonesandcameras),andtheycanonlybewrittentoafixednumberoftimes.ThecontrollerontheSSDmanagesthisforyou,buttheSSD'sperformancedegradesovertime.

Page 147: ASP.NET Core 1.0 High Performance

Aggressivewritingwillacceleratethisdegradation.

Multiplediskscanbecombinedtoimprovetheirperformanceandreliabilitycharacteristics.ThisiscommonlydoneusingatechnologycalledRedundantArrayofIndependentDisks(RAID).Dataissplitacrossmultiplediskstomakeitquickertoaccess,andmoretoleranttohardwarefailures.RAIDiscommoninserverhardware,butcanincreasethestartuptime,asSpin-upissometimesstaggeredtoreducethepeakpowerdraw.

HDDsoffermuchlargercapacitythanSSDs,andsoareagoodchoiceforstorageofinfrequentlyusedfiles.Youcangethybriddrives,whichcombineanHDDwithanSSD.Theseclaimtoofferthebestofbothworlds,andarecheaperthanSSDsofanequivalentsize.However,ifyoucanaffordit,andifyoucanfitallofyourdataonanSSD,thenyoushoulduseone.Youwillalsodecreaseyourpowerandcoolingrequirements,andyoucanalwaysaddanadditionalHDDformassstorageorbackups.

Virtualfilesystems

Fileaccesscanbeslowatthebestoftimesduetothephysicalnatureofthedisksstoringthedata,asmentionedpreviously.Thisproblemcanbecompoundedinavirtualizedenvironmentsuchasacloud-hostedinfrastructure.Thestoragedisksareusuallynotonthesamehostserverasthevirtualmachine,andwillgenerallybeimplementedasnetworkshareseveniftheyappeartobemountedlocally.Inanycase,thereisalwaysanadditionalproblem,whichispresentwhetherthediskisontheVMhostorsomewhereelseonthenetwork,andthatiscontention.

Onavirtualizedinfrastructure,suchasthoseprovidedbyAWSandAzure,yousharethehardwarewithotherusers,butaphysicaldiskcanonlyserviceasinglerequestatonce.Ifmultipletenantswanttoaccessthesamedisksimultaneously,thentheiroperationswillneedtobequeuedandtimeshared.Unfortunately,thisabstractionhasmuchthesamedetrimentaleffectonperformanceasreadinglotsofrandomfiles.Usersarelikelytohavetheirdataondiskstoredinlocationsdifferentfromothercustomers.Thiswillcausethearmonthedrivetofrequentlymovetodifferentsectors,reducingthroughputandincreasinglatencyforeveryoneonthesystem.

Allthismeansthatonsharedvirtualhosting,usinganSSDcanhaveabiggerpositiveperformanceimpactthannormal.EvenbetteristohavealocalSSD,whichisdirectlyattachedtotheVMhost,andnottoanothermachineonthenetwork.Ifdisksmustbenetworked,thenthestoragemachineshouldbeascloseaspossibletotheVMusingit.

YoucanpayextraforadedicatedVMhostwhereyouaretheonlytenant.However,youmayaswellthenberunningonbaremetal,andreapingthebenefitsofreducedcostsandhigherperformance.Ifyoudon'trequiretheeasyprovisioningandmaintenanceofVMs,thenabaremetaldedicatedservermaybeagoodoption.

ManycloudhostingprovidersnowofferSSDs,butmostonlyofferephemerallocaldisks.ThismeansthatthelocaldiskonlyexistswhileyourVMisrunning,andvanisheswhenitisshutdown,makingitunsuitableforstoringtheOSifyouwanttobringaVMbackupinthesamestate.

Page 148: ASP.NET Core 1.0 High Performance

Youhavetowriteyourapplicationinadifferentwaytotakeadvantageofanephemerallocaldrive,asitcoulddisappearatanytime,andsocanonlybeusedfortemporaryworkingstorage.Thisisknownasanimmutableserver,whichmeansitdoesn'tchangeandisdisposable.ThisnormallyworksbetterwhentheOSisLinux,asitcanbetrickytobootstrapnewinstanceswhenrunningWindows.

Databases

Databasescanbeslow,becausetheyrelyondisksforthestorageoftheirdata,butthereareotheroverheadsaswell.However,DBsareusuallyabetterwayofstoringsignificantdatathanflatfilesondisk.Arbitrarydatacanberetrievedquicklyifitisindexed,muchquickerthanscanningafilebybruteforce.

Relationaldatabasesareamatureandveryimpressivetechnology.However,theyonlyshinewhenusedcorrectly,andhowyougoaboutqueryingthemmakesamassivedifferencetoperformance.DBsaresoconvenientthatthey'reoftenoverused,andaretypicallythebottleneckforawebapplication.

Anunfortunatelycommonanti-patternisrequiringadatabasecallinordertorenderthehomepageofawebsite.AnexampleiswhenyoutrytovisitawebsitementionedonliveTV,onlytodiscoverthatithascrashedduetotheMySQLDBbeingoverloaded.Thissortofawebsitewouldbebetterarchitectedasastaticsitewiththeclient-sidecodehittingcachedandqueuedwebAPIs.

ThepathologicalcaseforaslowDBiswherethewebserverisinonedatacenter,thedatabaseserverisinanother,andthedisksfortheDBareinathird.Also,alltheserversmaybesharedwithotherusers.Obviously,it'sbestnottoendupinthissituation,andtoarchitectyourinfrastructureinasaneway,butyouwillalwayshavesomelatency.

ThereareapplicationprogrammingtechniquesthatallowyoutokeepyournetworkandDBchattertoaminimum.Thesehelpyoutoimprovetheperformanceandresponsivenessofyoursoftware,especiallyifitishostedinahigh-latencyvirtualizedenvironment.Wewilldemonstratesomeoftheseskillslateroninthischapter.

APIs

Modernwebapplicationprogramminggenerallyinvolvesusingthird-partyservicesandtheirassociatedAPIs.It'sbeneficialtoknowwheretheseAPIsarelocated,andwhatthelatencyis.Aretheyinthesamedatacenter,oraretheyontheothersideoftheplanet?Unlessyou'vediscoveredsomeexcitingnewphysics,thenlightonlytravelssofast.

Note

Today,almostallintercontinentaldatatravelsbyfiberopticscables.Satellitesarerarelyusedanymore,asthelatencyishigh,especiallyforgeostationaryorbits.Manyofthesecablesareundertheoceans,andarehardtofix.IfyourelyonanAPIonadifferentcontinent,notonlycanit

Page 149: ASP.NET Core 1.0 High Performance

slowyoudown,butitalsoexposesyoutoadditionalrisk.

Youprobablyshouldn'tbuildanimportantworkflowthatcanbedisruptedbyafishermantrawlinginthewrongplace.Youalsoneedtofurthersecureyourdata,assomecountries(suchastheUK)areknowntotapcablesandstorethecommunications,iftheycrosstheirborders.

OneoftheissueswithAPIsisthatlatencycancompound.YoumayneedtocallmanyAPIs,ormaybeanAPIcallsanotherAPIinternally.Thesesituationsarenotnormallydesignedthisway,butcangroworganicallyasnewfeaturesareadded,especiallyifnorefactoringisperformedperiodicallytotidyupanymess.

Onecommonformoflatencyisstartuptime.Websitescangotosleepifnotused,especiallyifusingthedefaultInternetInformationServices(IIS)settings.Ifawebsitetakesanon-negligibleamountoftimetowakeup,andalltherequiredAPIsalsoneedtowakeup,thenthedelayscanquicklyadduptoasignificantlagforthefirstrequest.Itmayeventime-out.

Thereareacoupleofsolutionstothisinitiallagproblem.IfyouuseIIS,thenyoucanconfiguretheapplicationpooltonotgotosleep.ThedefaultsinIISareoptimizedforsharedhosting,sotheywillneedtweakingforadedicatedserver.Thesecondoptionistokeepthesitealivebyregularlypollingitwithahealthcheckoruptimemonitoringtool.Youshouldbedoingthisanywaysothatyouknowwhenyoursitegoesdown,butyoushouldalsoensurethatyouareexercisingalltherequireddependencies(suchasAPIsandDBs).Ifyouaresimplyretrievingastaticpageorjustcheckingfora200statuscode,thenservicesmaygodownwithoutyourealizing.

Similarly,scalingcanhavealag.Ifyouneedtoscaleup,thenyoushouldpreheatyourloadbalancersandwebservers.ThisisespeciallyimportantifusinganAWSElasticLoadBalancer(ELB).Ifyou'reexpectingabigpeakintraffic,thenyoucanaskAWStohaveyourELBsprewarmed.AnalternativewouldbeusingAzureLoadBalancer,AzureApplicationGateway,orrunningHAProxyyourselfsothatyouhavemorecontrol.Youshouldalsoberunningloadtests,whichwe'llcoverinChapter9,MonitoringPerformanceRegressions.

Page 150: ASP.NET Core 1.0 High Performance

NetworkdiagnosticstoolsAswediscoveredearlier,practicallyallI/Ooperationsinavirtualizedorcloud-hostinginfrastructurearenownetworkoperations.Disksanddatabasesarerarelylocal,asthiswouldpreventscalingouthorizontally.Therearevariouscommand-linetoolsthatcanhelpyoudiscoverwheretheAPI,DB,oranyotherserveryou'reusingislocated,andhowmuchlatencyispresentontheconnection.

Whileallofthesecommandscanberunfromyourworkstation,theyaremostusefulwhenrunfromaserverviaaSecureShell(SSH)orRemoteDesktopProtocol(RDP)connection.Thisway,youcancheckwhereyourdatabases,APIs,andstorageserversare,inrelationtoyourwebservers.Unfortunately,itiscommonforhostingproviderstogeographicallyseparateyourservers,andputthemindifferentdatacenters.

Forexample,ifusingAWS,thenyouwouldwanttoconfigureyourserverstobeinatleastthesameregion,andpreferablyinthesameAvailabilityZone(AZ),whichusuallymeansthesamedatacenter.Youcanreplicate(cluster)yourDBorfileserveracrossAZs(orevenacrossregions)sothatyourwebserversarealwaystalkingtoaserverontheirlocalnetwork.Thisalsoaddsredundancy,soinadditiontoincreasingperformance,itwillmakeyourapplicationmoreresilienttohardwarefaultsorpowersupplyfailures.

Ping

Pingisasimplenetworkingdiagnosticstool,availableonalmostalloperatingsystems.ItoperatesattheIPlevelandsendsanInternetControlMessageProtocol(ICMP)echomessagetothehostspecified.

Notallmachineswillrespondtopings,orrequestsmaybeblockedbyfirewalls.However,it'sgoodnetiquettetoallowserverstorespondfordebuggingpurposes,andmostwilloblige.Forexample,openacommandpromptorterminal,andtypethefollowing:

pingec2.eu-central-1.amazonaws.com

ThiswillpinganAmazonWebServices(AWS)datacenterinGermany.Intheresponse,youwillseethetimeinmilliseconds.FromtheUK,thisround-triptime(RTT)maybesomethinglike33ms,butyourresultswillvary.

Tip

OnWindows,bydefault,pingperformsfourattempts,thenexits.OnaUnix-likeOS(suchasMacOSX,BSD,orLinux),bydefault,itcontinuesindefinitely.PressCtrl+Ctostopandquit.

Trythiscommandnext,whichwilldothesame,butforanAWSdatacenterinAustralia:

pingec2.ap-southeast-2.amazonaws.com

Page 151: ASP.NET Core 1.0 High Performance

FromtheUK,thelatencynowgoesup,byalmostanorderofmagnitude,toaround300ms.AWSdoesn'thaveanydatacentersintheUK,andneitherdoMicrosoftandGoogle(readintothatwhatyouwill).SotopingaUKhostingprovider,enterthefollowing:

pingbytemark.co.uk

Thelatencynowdecreasestoanaverageof23ms,asourconnectionhas(probably)notleftthecountry.Obviously,yourresultswillvarydependingonwhereyouare.Nextwe'llseehowtodiscoverwhatrouteourdataistaking,asit'snotalwaysonlydistancethat'simportant.Thenumberofhopscanlikewisebesignificant.

ThefollowingimageshowstheoutputofthethreepingoperationsthatwehavejustperformedtoGermany,theUK,andAustralia.Notethedifferenceinthetimings;however,yourresultswillbedifferent,sotrythisforyourself.

Tip

IPv4addressesstartingwith54(theonesintheform54.x.x.x)areacluethattheservermayberunningonanAWSElasticComputeCloud(EC2)virtualserver.PerformareverseDNSlookupwithnslookuporping(coveredlaterinthischapter)toconfirmifthisisthecase.AWSprovidesIPaddressrangesatthefollowinglink:docs.aws.amazon.com/general/latest/gr/aws-ip-

Page 152: ASP.NET Core 1.0 High Performance

ranges.html

Tracert

Tracert(ortracerouteonaUnix-likeOS)isatoolwhich,asthenamesuggests,tracestheroutetoadestinationhost.Enterthefollowingcommand:

tracertwww.google.com

YoushouldbeabletoseetheconnectionleavingthenetworkofyourInternetServiceProvider(ISP),andenteringthedomain1e100.net,whichisGoogle'sdomain.1.0x10100isagoogol,whichistheirnamesake.Thefollowingimageshowstheoutputthatyoumightseeforthistrace:

Next,let'stracearoutetoAustraliabyrunningthefollowingcommandwiththesameAWShostnameasourearlierexample,asfollows:

tracertec2.ap-southeast-2.amazonaws.com

Thismaytakesometimetorun,especiallyifsomehostsdon'trespondtopingsandtraceroutehastotimeout.Ifyougetasterisks(***),thenthiscouldindicatethepresenceofafirewall.Yourresultsmaylooksomethinglikethefollowingimage:

Page 153: ASP.NET Core 1.0 High Performance

Intheprecedingexample,wecanseetheconnectionleavingtheBritishTelecom(BT)network,andenteringtheNipponTelegraphandTelecom(NTT)GlobalIPNetwork.WecanevenseetheroutetakenfromLondontoSydney,viaAmsterdam,Ashburn(eastUS,inVirginia),andLosAngeles.ThehostnamessuggestthattheconnectionhasgoneviatheFaradaytelephoneexchangebuilding,nearSt.Paul'sCathedralinLondon(namedafterelectricalpioneerMichaelFaraday),andenteredAmazon'snetworkinLA.

Note

Thisisn'tthewholestoryasitonlyshowstheIPlevel.Atthephysicallevel,thefiberlikelycomesbacktotheUKfromtheNetherlands(possiblyviaPorthcurno,GoonhillySatelliteEarthStation,ormorelikely,BudewhereGCHQconvenientlyhaveabase).BetweenLAandAustralia,therewillalsoprobablybeastopoverinHawaii(wheretheNSAbasethatEdwardSnowdenworkedatislocated).

Therearemapsoftheconnectionsavailableatsubmarinecablemap.comandwww.us.ntt.net/about/network-map.cfm.It'sgoodideatohaveatleastabasicunderstandingofhowtheinternetisphysicallystructured,inordertoachievehighperformance.

IfwenowtracetheroutestotheAWSdatacentersinKoreaandJapan,wecanseethat,initially,theybothtakethesamerouteaseachother.TheygofromLondontoNewYorkandthentoSeattle,beforereachingOsakainJapan.TheKoreantracethencarriesonforanotherelevenhops,buttheJapanesetraceisdoneinsix,whichmakeslogicalsense.

ThefollowingimageshowsthetypicalresultsofatracetoKoreafirst,thentheresultsofa

Page 154: ASP.NET Core 1.0 High Performance

secondtracetoJapan.

Youcanusethedifferenceintimebetweenhopstoworkouttheapproximategeographicdistance.However,thereareoccasionallyanomaliesifsomesystemsrespondquickerthanothers.

Tip

Ifyou'reonaflightwithfreeWi-Fi,thenatracerouteisaninterestingexercisetoperform.The

Page 155: ASP.NET Core 1.0 High Performance

internetconnectionislikelygoingviasatellite,andyou'llbeabletotelltheorbitaltitudefromthelatency.Forexample,ageostationaryorbitwillhavealargelatencyofaround1,000ms,butaLowEarthOrbit(LEO)willbemuchsmaller.Youshouldalsobeabletoworkoutwherethegroundstationislocated.

Nslookup

NslookupisatoolfordirectlyqueryingaDNSserver.Digisanothersimilartool,butwewon'tcoverithere.BothpingandtraceroutehaveperformedDNSlookups,butyoucandothisdirectlywithnslookup,whichcanbeveryuseful.Youcancallnslookupwithcommand-lineparameters,butyoucanalsouseitinteractively.Todothis,simplytypethenameofthetoolintoaconsoleoracommandprompt,asfollows:

nslookup

Youwillnowgetaslightlydifferentcommandpromptfromwithintheprogram.Bydefault,theDNSnameserversofthecomputeryou'reonareused,anditbypassesanyentriesinyourlocalhostsfile.

Tip

AhostsfilecanbeveryusefulfortestingchangespriortoaddingthemtoDNS.Itcanalsobeusedasacrudeblockerforadvertsandtrackersbysettingtheiraddressesto0.0.0.0.TherearelocalDNSserversyoucanruntodothisforyourwholenetwork.Onesuchprojectispi-hole.net,whichisbasedondnsmasq,butwhichsimplifiessettingitupandupdatingthehostsonRaspberryPi.

EnterthehostnameofaservertoresolveitsIPaddress;forexample,typethefollowing:

polling.bbc.co.uk

TheresultsshowthatthishostnameisaCNAME(analiasfortherealCanonicalName)ofpolling.bbc.co.uk.edgekey.net,whichresolvestoe3891.g.akamaiedge.net,andthiscurrentlyhasanIPaddressof23.67.87.132.WecanperformareverseDNSlookupontheIPaddressbyenteringit:

23.67.87.132

Wethengetthehostnameofthatmachine,convenientlycontainingtheIPaddress,whichisa23-67-87-132.deploy.static.akamaitechnologies.com.ThedomainnameisownedbyAkamai,whichisaContentDeliveryNetwork(CDN)usedtodistributeload.

IfyouareusingaDNSserveronyourlocalnetwork,possiblywithyourrouterrunningdnsmasq,thenitmaycacheresults,andgiveyoustaledata.Youcanseemoreup-to-dateinformationbychangingtheservertoacoreonethatpropagateschangesquicker.Forexample,touseoneofGoogle'spublicDNSservers,enterthefollowing(butbeawarethatGooglewilllogalltheinternetsitesyouvisitifyouusethisnormally):

Page 156: ASP.NET Core 1.0 High Performance

server8.8.8.8

Thenrunthesamequeryagain.NoticehowthehostnamenowresolvestoadifferentIPaddress.ThisisacommonbehaviorforCDNs,andtherecordwillchangeovertime,evenonthesameDNSserver.Itisoftenusedasatechniquetobalancenetworkload.ChangingDNSserverscanalsosometimesbeusedtogetaroundNaïvecontentfiltersorlocationrestrictions.

Toexitthenslookupinteractivemode,typeexitandpressreturn.Thefollowingimageshowstheoutputforthepreviouscommands:

Note

IPv4istheversionofIPthatyouwillprobablybemostfamiliarwith.Ituses32-bitaddressesthatareusuallyrepresentedasfourdotteddecimaloctets,suchas192.168.0.1.However,wehaverunoutofIPv4addresses,andtheworldis(slowly)movingtothenewversionofIP,calledIPv6.Theaddresslengthhasincreasedfourfold,to128-bit,andisusuallyrepresentedinhexadecimalsuchas2001:0db8:0000:0000:0000:ee00:0032:154d.Leadingzeroscanbeomitted,like2001:db8::ee00:32:154d,tomakethemeasiertowrite.Localhostloopback(127.0.0.1)isnowsimply::1inIPv6.

OnWindows,youcanuseping-ax.x.x.xtodoareverseDNSlookup,andresolveIPaddressestohostnames.OnLinux(andonotherUnix-likesystemssuchasOSX),thisfeatureis

Page 157: ASP.NET Core 1.0 High Performance

notavailable,andthe-aflagservesadifferentpurpose.Youwillhavetousenslookup,ordigforreverseDNSontheseOSs.

Buildyourown

YoucanbuildyourowntoolsusingC#,andthefunctionsyouneedareprovidedby.NET.Thesearebuiltintothefull.NETFramework,butfor.NETCore,youwillneedtoaddtheNuGetpackageSystem.Net.Pingforping,althoughtheDNSnameresolutionisbuilt-in.Theunderlyingimplementationsareplatform-specific,buttheframeworkwilltakecareofcallingthenativecodeontheOSyou'reusing.

Youwon'tnormallyneedtoprogrammaticallyresolveahostname,asmostnetworkingcommandswilldothisautomatically.However,itcanoccasionallybeuseful,especiallyifyouwanttoperformareverseDNSlookup,andfindthehostnameforanIPaddress.

Tip

The.NETDnsclassdiffersfromnslookup,asitincludesentriesfromthelocalhostsfileratherthanjustqueryingaDNSserver.Itis,therefore,morerepresentativeoftheIPaddressesthatotherprocessesareresolving.

ToprogrammaticallyperformaDNSlookup,followthesesteps:

1. AddtheSystem.Netnamespace.

usingSystem.Net;

2. ToresolveahostnametoanIPaddress,usethefollowingstaticmethod.ThiswillreturnanarrayofIPaddresses,althoughtherewillusuallyonlybeone.

varresults=awaitDns.GetHostAddressesAsync(host);

3. ToresolveanIPaddresstoahostname,usethefollowingmethodinstead:

varrevDns=awaitDns.GetHostEntryAsync(result);

4. Ifsuccessful,thenthehostnamewillbeavailableasrevDns.HostName.

Toprogrammaticallypingahost,followthesesteps:

1. AddtheSystem.Net.NetworkInformationnamespace.

usingSystem.Net.NetworkInformation;

2. YoucantheninstantiateanewPingobject.

varping=newPing();

3. Withthisobject,youcannowpinganIPaddressorhostname(thatwillperformaDNSlookupinternally)byusingthefollowingmethod:

varresult=awaitping.SendPingAsync(host);

Page 158: ASP.NET Core 1.0 High Performance

4. Youcangetthestatusofthepingwithresult.Status,andifsuccessful,thenyoucangettheRTTinmillisecondswithresult.RoundtripTime.

Note

Thesourcecodeforourconsoleapplication,illustratinghowtousethe.NETCoreDnsandPingclasses,isavailablefordownloadalongwiththisbook.

AreverseDNSlookupcanusuallyrevealthehostingcompanybeingusedbyawebsite.Usually,thereisonlyoneIPaddressperhostname,asshowninthefollowingimageofour.NETCoreconsoleappoutput:

Intheprecedingscreenshot,wecanseethatemoncms.orgisusingredstation.comasahost.Thelowlatencysuggeststhattheserverislocatedinthesamecountryasourcomputer.

DNSisoftenusedforloadbalancing.Inthiscase,youwillseemanyIPaddressesreturnedforasingledomainname,asshowninthefollowingscreenshot:

Page 159: ASP.NET Core 1.0 High Performance

Wecanseeintheprecedingscreenshotthattheprivacy-focusedsearchengineDuckDuckGo(whichdoesn'ttrackitsuserslikeGoogledoes)isusingAWS.DNSisbeingusedtobalancetheloadacrossvariousinstances—inthiscase,they'reallintheDublindatacenter,becausethat'stheclosestone.NoticehowthepingtimesarenowslightlyhigherthantheUK-basedhostinthepreviousexample.

It'slikelythatthey'reusingtheAWSDNSserviceRoute53(sonamedbecauseDNSusesport53).Thiscanbalanceloadacrossregions,whereasanELB(whichDuckDuckGodoesn'tappeartobeusing)canonlybalanceinsidearegion(butbothinsideandacrossAZs).AzureoffersasimilarservicecalledTrafficManagerforDNSloadbalancing.

Page 160: ASP.NET Core 1.0 High Performance

SolutionsNowthatyouunderstandabitmoreaboutthecausesoflatency-basedproblems,andhowtoanalyzethem,wecandemonstratesomepotentialsolutions.Themeasurementsthatyouhavetakenusingthepreviouslyillustratedtoolswillhelpyouquantifythescaleoftheproblems,andchoosetheappropriatefixestobeapplied.

Page 161: ASP.NET Core 1.0 High Performance

BatchingAPIrequestsRenderingatypicalwebpagemayrequirecallstomanydifferentAPIs(orDBtables)togatherthedatarequiredforit.Duetothestyleofobject-orientedprogrammingencouragedbyC#(andmanyotherlanguages),theseAPIcallsareoftenperformedinseries.However,iftheresultofonecalldoesnotaffectanother,thenthisissuboptimal,andthecallscouldbeperformedinparallel.We'llcoverDBtableslaterinthischapter,astherearebetterapproachesforthem.

Concurrentcallscanbemorepertinentifyouimplementamicroservicesarchitecture(asopposedtothetraditionalmonolith,orbigballofmud),andhavelotsofdifferentdistributedendpoints.MessagequeuesaresometimesabetterchoicethanHTTPAPIsinmanycases,perhapsusingapublishandsubscribepattern.However,maybeyou'renotresponsiblefortheAPI,andareinsteadintegratingwithathirdparty.Indeed,iftheAPIisyours,thenyoucouldalterittoprovideallthedatathatyouneedinoneshotanyway.

ConsidertheexampleofcallingtwoisolatedAPIsthathavenodependenciesoneachother.Thesequencediagramforthismaylooksomethinglikethefollowing:

Page 162: ASP.NET Core 1.0 High Performance

ThislinearprocessofcallingA,andthencallingBwhenAisdone,issimple,asitrequiresnocomplexorchestrationtowrangletheresultsoftheAPIcalls,butitisslowerthannecessary.BycallingbothAPIssynchronouslyandinsequence,wewastetimewaitingforthemtoreturn.Abetterwayofdoingthis,ifwedon'trequiretheresultofthefirstAPIfortherequesttothesecond,maybetocallthemtogetherasynchronously.Thesequencediagramforthisnewflowmaylooksomethinglikethefollowing:

Page 163: ASP.NET Core 1.0 High Performance

Therearetwochangesinthisnewsequence,oneobviousandtheothersubtle.WecallbothAPIsasynchronouslyandinparallelsothattheyaresimultaneouslyinflight.Thisfirstchangewillhavethegreatestimpact,butthereisasmallertweakthatcanalsohelp,whichiscallingtheslowestAPIfirst.

Intheoriginalsequencediagram,wecallAPIAandthenAPIB,butBisslower.CallingAandBatthesametimewillhaveabigimpact,butcallingBandthenAisslightlybetter.Bdominatesthetimeline,andwewillbekillinga(relatively)largeamountoftimewaitingforit.

Page 164: ASP.NET Core 1.0 High Performance

WecanusethisdowntimetocallA,astherewillbesomesmallfixedoverheadinanyAPImethodcall.BothofthesechangescombinedmeanthatwearenowonlywaitingforB,andeffectivelygetthecalltoAforfree,intermsoftime.

Wecanillustratethisprinciplewithasimpleconsoleapplication.TherearetwomethodsthatsimulatetheAPIs,andbotharesimilar.APIAhasthefollowingcode:

privatestaticasyncTaskCallApiA()

{

Thread.Sleep(10);

awaitTask.Delay(100);

}

Thread.Sleepsimulatesthefixedoverhead,andTask.DelaysimulateswaitingfortheAPIcalltoreturn.APIBtakestwiceaslongtoreturnasAPIA,butthefixedoverheadisthesame,andithasthefollowingcode:

privatestaticasyncTaskCallApiB()

{

Thread.Sleep(10);

awaitTask.Delay(200);

}

Now,ifwesynchronouslycallthemethodsinsequence,wediscoverthatallofthedelaysaddup,asexpected.

CallApiA().Wait();

CallApiB().Wait();

Theseoperationstakeatotalofaround332msonaverage,asthereisabout10msofadditionalintrinsicoverheadinthemethodinvocation.Ifwecallbothmethodssimultaneously,thetimereducessignificantly.

Task.WaitAll(CallApiA(),CallApiB());

Theoperationsnowtakeanaveragetotalof233ms.Thisisgood,butwecandobetterifweswaptheorderofthemethods.

Task.WaitAll(CallApiB(),CallApiA());

Thisnowtakes,onanaverage,atotalof218ms,becausewehaveswallowedthefixedoverheadsofAPIAintothetimewearewaitingforAPIB.

Note

Thefullconsoleapplicationwhichbenchmarksthesethreevariantsisavailablefordownloadwiththisbook.ItusestheStopwatchclasstotimetheoperations,andaveragestheresultsovermanyruns.

Theresultsofthesethreedifferentapproachesareshowninthefollowingimage:

Page 165: ASP.NET Core 1.0 High Performance

Asisalwaysthecase,measureyourresultstomakesuretherereallyisanimprovement.YoumayfindthatifyouaremakingmanycallstooneAPI,orreusingthesameAPIclient,thenyourrequestsareprocessedsequentially,regardless.

ThisparallelizingoftasksnotonlyworksforI/O,butcanalsobeusedforcomputation,aswewilldiscoverinthenextchapter.Fornow,wewillmoveon,andtakeadeeperlookatdatabasequeryoptimization.

Page 166: ASP.NET Core 1.0 High Performance

EfficientDBoperationsAlthoughthisisn'tabookaimedatDatabaseAdministrators(DBAs),it'sadvantageousforyoutoappreciatetheunderlyingtechnologythatyou'reusing.Asisthecasewithnetworking,ifyouunderstandthestrengthsandweaknesses,thenyoucanachievehighperformancemoreeasily.

Thisisadditionallyrelevantfortherecenttrendofdevelopersdoingmoreworkoutsideoftheirspecialization,particularlyinsmallorganizationsorstartups.Youmayhaveheardthebuzzwordsfull-stackdeveloperorDevOps.Theserefertorolesthatblurthetraditionalboundaries,andmergedevelopment(bothfrontendandbackend),qualityassurance,networking,infrastructure,operations,anddatabaseadministrationintoonejob.Beingadevelopertodayisnolongeracaseofjustprogrammingorshippingcode.Ithelpstoknowsomethingabouttheotherareastoo.

Previously,inChapter3,FixingCommonPerformanceProblems,wecoveredusingthemicroO/RMDapper,andhowtofixSelectN+1problems.Now,we'llbuildonthatknowledge,andhighlightafewmorewaysthatyoucanconsolidatequeriesandimprovetheperformanceofyourDBoperations.

AsdetailedinChapter2,MeasuringPerformanceBottlenecks,thefirststepistoprofileyourapplicationanddiscoverwheretheissueslie.Onlythenshouldyoumoveontoapplyingsolutionstotheproblemareas.

Databasetuning

We'regoingtofocusmoreonimprovingpoorlyperformingqueries,sowewon'tgointoDBtuningtoomuch.Thisisacomplextopic,andthereisalotyoucanlearnaboutindexesandhowdataisstored.

However,ifyouhaven'truntheDatabaseEngineTuningAdvisor(DETA),thenthisisaneasysteptoidentifyifyouhaveanymissingindexes.Yet,youshouldbecarefulwhenapplyingtherecommendedchanges,astherearealwaysdownsidesandtradeoffstoconsider.Forexample,indexesmakeretrievingdataquicker,butalsomakeitslowertoaddandupdaterecords.Theyalsotakeupadditionalspace,soitisbestnottooverdoit.Itwilldependonyourparticularbusinessusecase:ifyouwishtooptimizeupfront,ortakethehitlateronretrieval.

ThefirststepistocaptureatracewithSQLServerProfiler.SeeChapter2,MeasuringPerformanceBottlenecksforhowtodothis,andsavetheresultingfile.Thisisoneofthereasonsthatthetuningprofileisagoodchoice.YoushouldmakesurethatthetraceisrepresentativeofagenuineDBusetogetgoodresults.YoucanlaunchtheDETAfromthesamemenuastheprofilerinSSMS.

Page 167: ASP.NET Core 1.0 High Performance

Youcanthenloadinyourtraceasaworkload,andafterprocessing,itwillgiveyousomerecommendations.Wewon'tcoverthedetailsofhowtodothishereforspacereasons,anditisprettyself-explanatory.Therearemanygoodguidesavailableonline,ifrequired.

Reporting

Acommonusecase,whichcanoftenbringadatabasetoitsknees,isreporting.Reportsusuallyrunonlargeamountsofdata,andcantakeconsiderabletimeifpoorlywritten.

IfyoualreadyhaveamethodforretrievingasingleitemfromaDB,thenitcanbetemptingtoreusethisforreportingpurposesandforcalculatingmetricsinsideoftheapplication.However,thisisbestavoided;reportsshouldgenerallyhavetheirowndedicatedqueries.

Evenbetteristohaveanotherdatabasededicatedtoreporting,whichispopulatedfromthemainDBorfrombackups.Thisway,intensivereportswon'taffecttheperformanceofthemainapplicationattheexpenseofnotincludingreal-timedata.Thisissometimesknownasadatawarehouseordatamart,andthedataisoccasionallydenormalizedforsimplicityorperformancereasons.PopulatinganotherDBcanalsobeaconvenientwaytotestyourbackups,asdatabasebackupsshouldalwaysbetestedtoensurethattheycanberestoredcorrectlyandcontainalloftherequireddata.

Note

Intheensuingexamples,wewillfocusonMicrosoftSQLServer(MSSQL)andtheTransact-SQL(T-SQL)dialectofSQL.Otherdatabases,suchasPostgreSQL,areavailableaswell.PostgreSQLhasitsowndialectcalledProceduralLanguage/PostgreSQL(PL/pgSQL),whichissimilartoOraclePL/SQL.ThesedialectsallsupportbasicSQLcommands,butusedifferentsyntaxforsomeoperations,andcontaindifferentoradditionalfeatures.

ThelatestversionofMSSQLServerisSQLServer2016,andit'sthefirsteditiontosupportrunningonLinuxinadditiontoWindows.ItisbasedontheSQLAzureservicecode,sothereshouldnowbefewerdifferencesbetweenaself-hosted,on-premiseDBandMicrosoft'scloudoffering.

Page 168: ASP.NET Core 1.0 High Performance

Aggregates

AggregatefunctionsareanincrediblyusefulfeatureofaRDBMS.Youcancomputevaluesthatsummarizemanyrecordsinthedatabase,andonlyreturntheresultkeepingthesourcedatarowsintheDB.

YouwillbefamiliarwiththeCOUNTaggregatefunctionfromearlierinthebook,ifnotbefore.Thisgivesyouthetotalnumberofrecordsreturnedbyyourquery,butwithoutreturningthem.YoumayhavereadadvicethatCOUNT(1)performsbetterthanCOUNT(*),butthisisnolongerthecase,asSQLServernowoptimizesthelattertoperformthesameastheformer.

Tip

Bydefault,SQLServerwillreturnamessagedetailingthecountoftherecordsreturned,alongwiththeresultofeveryquery.YoucanturnthisoffbyprefixingyourquerywiththeSETNOCOUNTONcommand,whichwillsaveafewbytesintheTabularDataStream(TDS)connection,andincreaseperformanceslightly.Thisissignificantonlyifacursorisbeingused,whichisbadpracticeanywayforlockingreasons.It'sgoodpracticetore-enablerowcountafterthequery,eventhoughitwillberesetoutsideofthelocalscopeanyway.

InChapter3,FixingCommonPerformanceProblems,wesolvedourSelectN+1problembyjoiningtablesintheDB,andusingCOUNTinsteadofperformingthesecalculationsinourapplicationcode.Therearemanyotheraggregatefunctionsavailable,thatcanbeusefulinimprovingperformance,especiallyforreportingpurposes.

Goingbacktoourearlierexample,supposewenowwanttofindoutthetotalnumberofblogposts.Wealsowanttofindthetotalnumberofcomments,theaveragecommentcount,thelowestnumberofcommentsforasinglepost,andthehighestnumberofcommentsforasinglepost.

Thefirstpartiseasy—justapplyCOUNTtothepostsinsteadofthecomments—€”butthesecondpartisharder.Aswealreadyhaveourlistofpostswithacommentcountforeach,itmaybetemptingtoreusethat,andsimplyworkeverythingoutinourC#code.

Thiswouldbeabadidea,andthequerywouldperformpoorly,especiallyifthenumberofpostsishigh.Abettersolutionwouldbetouseaquerysuchasthefollowing:

;WITHPostCommentCountAS(

SELECT

bp.BlogPostId,

COUNT(bpc.BlogPostCommentId)'CommentCount'

FROMBlogPostbp

LEFTJOINBlogPostCommentbpc

ONbpc.BlogPostId=bp.BlogPostId

GROUPBYbp.BlogPostId

)SELECT

COUNT(BlogPostId)'TotalPosts',

SUM(CommentCount)'TotalComments',

AVG(CommentCount)'AverageComments',

Page 169: ASP.NET Core 1.0 High Performance

MIN(CommentCount)'MinimumComments',

MAX(CommentCount)'MaximumComments'

FROMPostCommentCount

ThisqueryusesaCommonTableExpression(CTE),butyoucouldalsouseanestedSELECTtoembedthefirstqueryintotheFROMclauseofthesecond.Itillustratesaselectionoftheaggregatefunctionsavailable,andtheresultsonthetestdatabasefrombeforelooklikethefollowing:

Note

Thesemicolonatthestartissimplyagoodpracticetoavoiderrorsandremoveambiguity.Itensuresthatanypreviouscommandhasbeenterminated,asWITHcanbeusedinothercontexts.Itisn'trequiredfortheprecedingexample,butmightbeifitwerepartofalargerquery.CTEscanbeveryusefultools,especiallyifyourequirerecursion.However,theyareevaluatedeverytime,soyoumayfindthattemporarytablesperformmuchbetterforyou,especiallyifqueryingonerepeatedlyinanestedSELECT.

Nowsupposethatwewishtoperformthesamequery,butonlyincludepoststhathaveatleastonecomment.Inthiscase,wecoulduseaquerylikethefollowing:

;WITHPostCommentCountAS(

SELECT

bp.BlogPostId,

COUNT(bpc.BlogPostCommentId)'CommentCount'

FROMBlogPostbp

LEFTJOINBlogPostCommentbpc

ONbpc.BlogPostId=bp.BlogPostId

GROUPBYbp.BlogPostId

HAVINGCOUNT(bpc.BlogPostCommentId)>0

)SELECT

COUNT(BlogPostId)'TotalPosts',

SUM(CommentCount)'TotalComments',

AVG(CommentCount)'AverageComments',

MIN(CommentCount)'MinimumComments',

MAX(CommentCount)'MaximumComments'

FROMPostCommentCount

WehaveaddedaHAVINGclausetoensurethatweonlycountpostswithmorethanzerocomments.ThisissimilartoaWHEREclause,butforusewithaGROUPBY.Thequeryresultsnowlooksomethinglikethefollowing:

Page 170: ASP.NET Core 1.0 High Performance

Sampling

Sometimes,youdon'tneedtouseallofthedata,andcansampleit.Thistechniqueisparticularlyapplicabletoanytime-seriesinformationthatyoumaywishtograph.InSQLServer,thetraditionalwaytoperformrandomsamplingwasusingtheNEWID()method,butthiscanbeslow.Forexample,considerthefollowingquery:

SELECTTOP1PERCENT*

FROM[dbo].[TrainStatus]

ORDERBYNEWID()

Thisqueryreturnsexactly1%oftherowswitharandomdistribution.Whenrunagainstatablewith1,205,855entries,itreturned12,059resultsinaboutfourseconds,whichisslow.AbetterwaymaybetouseTABLESAMPLE,whichisavailableinanyreasonablyrecentversionofSQLServer(2005onwards),asfollows:

SELECT*

FROM[dbo].[TrainStatus]

TABLESAMPLE(1PERCENT)

Thisprecedingqueryismuchquicker,andwhenrunagainstthesamedataasthepreviousexample,itcompletesalmostinstantly.Thedownsideisthatit'scruderthantheearliermethod,anditwon'treturnexactly1%oftheresults.Itwillreturnroughly1%,butthevaluewillchangeeverytimeitisrun.Forexample,runningagainstthesametestdatabase,itreturned11,504,13,441and11,427rowswhenexecutingthequerythreetimesinarow.

Insertingdata

Queryingdatabasesmaybethemostcommonusecase,butyouwillusuallyneedtoputsomedatainthereinthefirstplace.OneofthemostcommonlyusedfeatureswheninsertingrecordsintoarelationalDBistheidentitycolumn.Thisisanauto-incrementingIDthatisgeneratedbythedatabase,anddoesn'tneedtobesuppliedwhenaddingdata.

Forexample,inourBlogPosttablefromearlier,theBlogPostIdcolumniscreatedasINTIDENTITY(1,1).Thismeansthatit'sanintegervaluestartingatoneandincreasingbyoneforeverynewrow.YouINSERTintothistable,withoutspecifyingBlogPostId,likeso:

INSERTINTOBlogPost(Title,Content)

VALUES('MyAwesomePost','Writesomethingwittyhere...')

Identitiescanbeveryuseful,butyouwillusuallywanttoknowtheIDofyournewlycreatedrecord.Itistypicaltowanttostorearow,thenimmediatelyretrieveitsothattheIDcanbeused

Page 171: ASP.NET Core 1.0 High Performance

forfutureeditingoperations.YoucandothisinoneshotwiththeOUTPUTclause,likeso;

INSERTINTOBlogPost(Title,Content)

OUTPUTINSERTED.BlogPostId

VALUES('MyAwesomePost','Writesomethingwittyhere...')

Inadditiontoinsertingtherow,theIDwillbereturned.

Note

YoumayseeSCOPE_IDENTITY()(oreven@@IDENTITY)advocatedaswaysofretrievingtheidentity,buttheseareoutdated.Therecommendedwayofdoingthis,onmodernversionsofSQLServer,istouseOUTPUT.

OUTPUTworksontheINSERT,UPDATE,DELETE,andMERGEcommands.Itevenworkswhenoperatingonmultiplerowsatatime,asinthisexampleofbulkinsertingtwoblogposts:

INSERTINTOBlogPost(Title,Content)

OUTPUTINSERTED.BlogPostId

VALUES('MyAwesomePost','Writesomethingwittyhere...'),

('MySecondAwesomePost','Tryharderthistime...')

Theprecedingquerywillreturnaresultsetoftwoidentities,forexample,3003and3004.InordertoexecutetheseinsertswithDapper,youcanusethefollowingmethodforasinglerecord.First,letuscreateablogpostobject,whichwe'llhardcodehere,butwhichwouldnormallycomefromuserinput:

varpost=newBlogPost

{

Title="MyAwesomePost",

Content="Writesomethingwittyhere..."

};

Toinsertthisonepost,andsettheID,youcanusethefollowingcode.Thiswillexecutetheinsertstatement,andreturnasingleintegervalue.

post.BlogPostId=awaitconnection.ExecuteScalarAsync<int>(@"

INSERTINTOBlogPost(Title,Content)

OUTPUTINSERTED.BlogPostId

VALUES(@Title,@Content)",

post);

YoucanthenassignthereturnedIDtothepost,andreturnthatobjecttotheuserforediting.Thereisnoneedtoselecttherecordagain,assumingtheinsertsucceedsandnoexceptionsarethrown.

YoucaninsertmultiplerecordsatoncewiththesameSQLbyusingtheexecutemethod.However,theSQLwillbeexecutedmultipletimes,whichmaybeinefficient,andyouonlygetbackthenumberofinsertedrows,nottheirIDs.ThefollowingcodesuppliesanarrayofpoststothesameSQLusedinthepreviousexample:

varnumberOfRows=awaitconnection.ExecuteAsync(@"

Page 172: ASP.NET Core 1.0 High Performance

INSERTINTOBlogPost(Title,Content)

OUTPUTINSERTED.BlogPostId

VALUES(@Title,@Content)",

new[]{post,post,post});

IfyouwantmultipleIDsreturned,thenyouwillneedtousethequerymethodtoreturnacollectionofvalues,aswehavedonepreviously.However,itisdifficulttomakethisworkforavariablenumberofrecords,withoutdynamicallybuildingSQL.Thefollowingcodeperformsabulkinsert,usingmultipleseparateparametersforthequery:

varids=awaitconnection.QueryAsync<int>(@"

INSERTINTOBlogPost(Title,Content)

OUTPUTINSERTED.BlogPostId

VALUES(@Title1,@Content1),

(@Title2,@Content2)",new

{

Title1=post.Title,

Content1=post.Content,

Title2=post.Title,

Content2=post.Content

});

Thiswillperformalltheworkinasinglecommand,andreturnanenumerablecollectionoftheidentities.However,thiscodeisnotveryscalable(orevenelegant).

Tip

TherearemanyhelpermethodsintheDapper.Contribpackagewhichcanassistyouwithinsertingrecordsandotheroperations.However,theysufferfromthesamelimitationsastheexampleshere,andyoucanonlyreturnasingleidentityorthenumberofrowsinserted.

GUIDs

Integeridentitiescanbeusefultoadatabaseinternally,butperhapsyoushouldn'tbeusinganidentifyingkeyexternally,especiallyifyouhavemultiplewebserversorexposetheIDstousers.AnalternativeistouseaGloballyUniqueIdentifier(GUID),referredtoasUNIQUEIDENTIFIERinSQLServer.Wehavealreadytouchedonthese,astheyaregeneratedbytheNEWID()functionusedinthesuboptimalsamplingexample.

GUIDsareusedubiquitously,andare16byteslong—fourtimesbiggerthananinteger.ThesizeofGUIDsmeansthatyouareunlikelytogetauniqueconstraintconflictwheninsertingarandomGUIDintoanalreadypopulatedtable.

Note

PeoplesometimesworryaboutGUIDcollisions,butthenumbersinvolvedaresostaggeringlyhugethatcollisionsareincrediblyunlikely.TheGUIDsgeneratedby.NET(usingaCOMfunctiononWindows)are,specifically,UniversallyUniqueIdentifiers(UUIDs)version4.Thesehave122bitsofrandomness,soyouwouldneedtogeneratenearlythreebillionGUIDsbeforehavingevenhalfachanceofacollision.

Page 173: ASP.NET Core 1.0 High Performance

Atonenewrecordpersecond,thatwouldtakeover90billionyears.EvenattwomillionGUIDspersecond(whatanaveragecomputertodaycouldproduce),itwouldstilltakeover45thousandyears(moretimethanhumancivilizationhasbeenaround).Ifyouthinkthatthiswillbeanissueforyoursoftware,thenyoushouldprobablybefuture-proofingitbyusingfive-digityears,suchas02016,toavoidtheY10K(orYAKinhexadecimal)problem.

ThisuniquenesspropertyallowsyoutogenerateaGUIDinyourapplicationcodeandstoreitinadistributeddatabase,withoutworryingaboutmergingdatalater.ItalsoallowsyoutoexposeIDstousers,withoutcaringifsomeonewillenumeratethemortryandguessavalue.IntegerIDsoftenexposehowmanyrecordsthereareinatable,whichcouldbesensitiveinformationdependingonyourusecase.

OnethingyouhavetowatchoutforwithrandomGUIDsisusingthemaskeys,asopposedtoIDs.Thedifferencebetweenthesetwotermsissubtle,andtheyareoftenoneandthesame.Thekey(primaryorclustered)iswhattheDBusestoaddressarecord,whereastheIDiswhatyouwouldusetoretrieveone.Thesecanbethesamevaluebuttheydon'thavetobe.UsingarandomGUIDasakeycancauseperformanceissueswithindexing.Therandomnessmaycausefragmentation,whichwillslowdownqueries.

YoucanusesequentialGUIDs,forexampleNEWSEQUENTIALID()canbetheDEFAULTvalueforacolumn,butthenyoulosemostofthebeneficialqualitiesofGUIDsthatmainlycomefromtherandomness.Younoweffectivelyjusthaveareallybiginteger,andifyou'reonlyconcernedwiththemaximumnumberofrowsinatable,andrequiremorethantwobillion,thenabigint(twiceanint,buthalfaGUID)shouldsuffice.

Agoodcompromiseistohaveanintidentityastheprimarykey,buttouseaGUIDastheID(andenforcethiswithauniqueconstraintonthecolumn).It'sbestifyougeneratetheGUIDinapplicationcodewithGuid.NewGuid(),asusingadefaultcolumnvalueintheDBmeansyouhavetoretrievetheIDafteraninsert,asshownpreviously.

Atableusingthisstrategymaypartiallylooksomethinglikethefollowingimage.ThisisascreencaptureofpartofatablefromtheMembershipRebootusermanagementandauthenticationlibrary:

AdvancedDBtopics

Page 174: ASP.NET Core 1.0 High Performance

Therearemanyotherdatabaseperformanceenhancingtechniquesthatwecouldcoverhere,butdon'thavespacefor.We'llbrieflymentionsomeadditionaltopicsincaseyouwanttolookintothemfurther.

Acommonrequirementwhensavingdataistoinsertarecordifitdoesn'tyetexist,ortoupdateanexistingrecordifthereisalreadyarowcontainingthatID.Thisissometimesreferredtoasanupsert,whichisaportmanteauwordcombiningupdateandinsert.

YoucanusetheMERGEcommand,todothisinoneoperationandnotworryaboutchoosingbetweenUPDATEorINSERT(wrappedinatransactioninsideastoredprocedure).However,MERGEdoesnotperformaswellasUPDATEorINSERT,soalwaystesttheeffectsforyourusecase,anduseitsparingly.

Storedprocedures,transactions,andlockingareallbigsubjectsontheirown.Theyareimportanttounderstand,andnotonlyfromaperformanceperspective.Wecan'tfitalloftheseinhere,butwewilltouchuponmaintainingstoredprocedureslaterinthebook.

Someothertechniquesyoucouldlookintoarecross-databasejoins,whichcansaveyoufromqueryingmultipleDBs.Thereisalsothepracticeofdenormalizingyourdata,whichinvolvesflatteningyourrelationalrecordsaheadoftimetoprovideasinglerowratherthanneedingtojoinacrossmanytablesforaquery.Webrieflymentionedthisinrelationtodatawarehousesearlier.

Note

YoucanfindlotsofusefulSQLdocumentationandinformationonMSDN(msdn.microsoft.com)andTechNet(technet.microsoft.com).Additionally,therearemanygoodbooksonadvancedSQLtechniques.

Finally,anoteonhousekeeping.It'simportanttohaveaplanformanagingthesizeofadatabase.Youcan'tsimplykeepinsertingdataintoatable,andhopeitwillcontinuetoperformwellforever.Atsomepoint,itwillgetsolargethatevendeletingrecordsfromitwillcauseyourDBtogrindtoacrawl.Youshouldknowaheadoftimehowyouwillremoveorarchiverows,anditisbettertodothisregularlyinsmallbatches.

Page 175: ASP.NET Core 1.0 High Performance

SimulationandtestingTowrapupthischapter,let'sreiteratetheimportanceofbeingabletotestyourapplicationonrealisticinfrastructure.Yourtestenvironmentsshouldbeaslive-likeaspossible.Ifyoudon'ttestonequivalentDBsandnetworks,thenyoumaygetanastysurprisecomedeploymenttime.

Whenusingacloudhostingprovider(andifyouautomateyourserverbuilds),thenthisiseasy:youcansimplySpin-upastagingsystemthatmatchesproduction.Youdon'thavetoprovisionittotheexactsamescaleaslongasallthepartsarethereandinthesameplace.Toreducecostsfurther,youonlyneedtokeepitaroundforaslongasyourtest.

Alternatively,youcouldcreateanewliveenvironment,deployandtestit,thenswitchover,anddestroyorreusetheoldliveenvironment.Thisswappingtechniqueisknownasblue-greendeployment.Anotheroptionistodeploynewcodebehindafeatureswitch,whichallowsyoutotogglethefeatureatruntime,andonlyforsomeusers.Notonlydoesthisallowyoutofunctionallyverifyfeatureswithtestusers,youcanalsograduallyrolloutanewfeature,andmonitortheperformanceimpactasyoudoso.WewillcoverbothofthesetechniquesinChapter9,MonitoringPerformanceRegressions.

Page 176: ASP.NET Core 1.0 High Performance

SummaryWe'vecoveredalotinthischapter,anditshouldhopefullybeclearthatbeingahighperformancedeveloperrequiresmorethansimplybeingacapableprogrammer.Therearemanyexternalitiestoconsideraroundyourcode.

YounowunderstandthebasicsofI/O,andthephysicalcausesoftheintrinsiclimitationspresent.Youcananalyzeanddiagnosehowanetworklogicallyfitstogether.Wehavecoveredhowtomakebetteruseofthenetworktoreduceoveralllatency,whichisimportantasmoreI/Ooperationsnowhappenoveranetwork.Youhavealsoseenhowtomakebetteruseofadatabase,andhowtodomorewithfeweroperations.

Inthenextchapter,wewilldigintocodeexecutionindetail,andshowyouhowtospeedupyourC#.We'llseehow.NETCoreandASP.NETCoreperformsomuchbetterthanthepreviousversions,andhowyoucantakeadvantageoftheseimprovements.

Page 177: ASP.NET Core 1.0 High Performance

Chapter6.UnderstandingCodeExecutionandAsynchronousOperationsThischaptercoverssolvingperformanceproblemsintheexecutionofyourcode,whichisnotnormallythefirstlocationthatspeedissuesoccur,butcanbeagoodadditionaloptimization.We'lldiscusstheareaswhereperformanceisneeded,andwhereitisokay(orevenrequired)tobeslow.Themeritsofvariousdatastructureswillbecomparedfromthestandardbuilt-ingenericcollectionstothemoreexotic.Wewilldemonstratehowtocomputeoperationsinparallel,andhowtotakeadvantageofextrainstructionsetsthatyourCPUmayprovide.We'lldiveintotheinternalsofASP.NETCoreand.NETCoretohighlighttheimprovementsthatyoushouldbeawareof.

Thetopicscoveredinthischapterincludethefollowing:

.NETCoreandthenativetoolchainCommonLanguageRuntime(CLR)servicessuchasGC,JIT,andNGenASP.NETCoreandtheKestrelwebserverGenericcollectionsandBloomfiltersSerializationanddatarepresentationformatsRelativeperformanceofhashingfunctionsParallelization(SIMD,TPL,andPLINQ)Poorlyperformingpracticestoavoid

Youwilllearnhowtocomputeresultsinparallelandcombinetheoutputsattheend.Thisincludeshowtoavoidincorrectwaysofdoingthis,whichcanmakethingsworse.You'llalsolearnhowtoreduceserverutilization,andtochoosethemostappropriatedatastructuresinordertoprocessinformationefficientlyforyourspecificsituation.

Page 178: ASP.NET Core 1.0 High Performance

GettingstartedwiththecoreprojectsTherearemanybenefitsofusing.NETCoreandASP.NETCoreovertheoldfullversionsoftheframeworks.Themainenhancementsaretheopensourcedevelopmentandcrossplatformsupport,buttherearealsosignificantperformanceimprovements.Opendevelopmentisimportantandthesourcecodeisnotonlyavailable,thedevelopmentworkhappensintheopenonGitHub.Thecommunityisencouragedtomakecontributionsandthesemaybemergedinupstreamiftheypassacodereview;theflowisn'tjustoneway.ThishasledtoincreasedperformanceandadditionalplatformsupportcomingfromoutsideofMicrosoft.Ifyoufindabuginaframework,youcannowfixitratherthanworkaroundtheproblemandhopeforapatch.

ThemultipleprojectsthatmakeuptheframeworksaresplitacrosstwoorganizationsonGitHub.Oneofthedrivingprincipleshasbeentosplittheframeworksupintomodules,soyoucanjusttakewhatyouneedratherthanthewholemonolithicinstallation.Thelowerlevelframework,.NETCore,canbefound,alongwithotherprojects,undergithub.com/dotnet.Thehigherlevelwebapplicationframework,ASP.NETCore,canbefoundundergithub.com/aspnet.Thereasonforthissplitisthat.NETCoreismanagedbythe.NETFoundationwhichisanindependentorganization,althoughmostofthemembersareMicrosoftstaff.ASP.NETCoreismanageddirectlybyMicrosoft.

Let'shaveaquicklookatsomeofthevarious.NETCorerepositoriesandhowtheyfittogether.

Page 179: ASP.NET Core 1.0 High Performance

.NETCoreThereareacoupleofprojectsthatformthemainpartsof.NETCoreandtheseareCoreCLRandCoreFX.CoreCLRcontainsthe.NETCoreCLRandthebasecorelibrary,mscorlib.TheCLRisthevirtualmachinethatrunsthe.NETcode.CoreCLRcontainsajust-in-time(JIT)compiler,GarbageCollector(GC),andalsobasetypesandclassesinmscorlib.CoreFXincludesthefoundationallibrariesandsitsontopofCoreCLR.Thisincludesmostbuilt-incomponentsthataren'tsimpletypes.

Note

Youmaybefamiliarwiththe<gcServer>elementusedtosetaGCmode,moresuitableforserveruse,withshorterpauses.Youcanreadmoreabouttheoriginalversionatmsdn.microsoft.com/en-us/library/ms229357.In.NETCoreyoucansettheCOMplus_gcServerenvironmentvariableto1orsetSystem.GC.ServertotrueasaruntimeoptioninaJSONruntimeconfigurationfile.

It'sworthhighlightinganotherprojectcalledCoreRT,whichisaruntimethatallowsahead-of-time(AOT)compilation,insteadoftheJITofCoreCLR.ThismeansthatyoucancompileyourC#codetonativemachinecode,andrunitwithoutanydependencies.Youendupwithasingle(staticallylinked)binaryanddon'tneed.NETinstalled,whichisverysimilartohowGooperates.WiththeRoslyncompiler,younolongeralwaysneedtocompiletoCommonIntermediateLanguage(CIL)bytecodethenhavetheCLRJITcompiletonativeinstructionsatruntimewithRyuJIT.

Thisnativetoolchainallowsforperformanceimprovements,asthecompilationdoesnothavetohappenquickly,inrealtime,andcanbefurtheroptimized.Forexample,abuildcanbetunedforexecutionspeedattheexpenseofcompilationspeed.It'sconceptuallysimilartotheNativeImageGenerator(NGen)tool,whichhasbeeninthefull.NETFrameworksinceitsinception.

Page 180: ASP.NET Core 1.0 High Performance

ASP.NETCoreASP.NETCorerunsontopof.NETCore,althoughitcanalsorunonthefull.NETFramework.Wewillonlycoverrunningon.NETCore,asthisperformsbetterandensuresenhancedplatformsupport.TherearemanyprojectsthatmakeupASP.NETCoreandit'sworthbrieflymentioningsomeofthem.

Tip

It'susefultonotincludeanyframeworkreferencesto.NET4.5/4.6inyourproject,sothatyoucanbesureyou'reonlyusing.NETCoreanddon'taccidentallyreferenceanydependenciesthatarenotyetsupported.

ASP.NETCoreincludesModelViewController(MVC),WebAPI,andWebPages(awaytomakesimplepageswithRazor,similartoPHP,andthespiritualsuccessortoclassicASP).Thesefeaturesareallmergedtogether,soyoudon'tneedtothinkofMVCandWebAPIasseparateframeworksanymore.Therearemanyotherprojectsandrepositories,includingEFCore,buttheonewewillhighlighthereistheKestrelHTTPserver.

Kestrel

KestrelisanewwebserverforASP.NETCoreanditperformsbrilliantly.It'sbasedonlibuv,whichisanasynchronousI/OabstractionandsupportlibrarythatalsorunsbelowNode.js.Kestrelisblazinglyfast,andthebenchmarksareveryimpressive.However,itisprettybasic,andforproductionhosting,youshouldputitbehindareverseproxy,sothatyoucanusecachingandotherfeaturestoserviceagreaternumberofusers.YoucanusemanyHTTPorproxyserversforthispurposesuchasIIS,NGINX,Apache,orHAProxy.

Tip

YoushouldbecarefulwithyourconfigurationifusingNGINXasareverseproxy,asbydefault,itwillretryPOSTrequestsiftheresponsefromyourwebservertimesout.Thiscouldresultinduplicateoperationsbeingperformed,especiallyifusedasaloadbalanceracrossmultiplebackendHTTPservers.

Page 181: ASP.NET Core 1.0 High Performance

DatastructuresDatastructuresareobjectsthatyoucanusetostoretheinformationyou'reworkingon.Choosingthebestimplementationforhowyourdataisusedcanhavedramaticeffectsonthespeedofexecution.Here,we'lldiscusssomecommonandsomemoreinterestingdatastructuresthatyoumightliketomakeuseof.

Asthisisabookaboutwebapplicationprogrammingandnotoneoncomplexalgorithmimplementationormicro-optimization,wewon'tbegoingintoahugeamountofdetailondatastructuresandalgorithms.Asbrieflymentionedintheintroduction,otherfactorscandwarftheexecutionspeedinawebcontext,andweassumeyou'renotwritingagameengine.However,goodalgorithmscanhelpspeedupapplications,so,ifyouareworkinginanareawhereexecutionperformanceisimportant,youshouldreadmoreaboutthem.

We'remoreinterestedintheperformanceofthesystemasawhole,notnecessarilythespeedthecoderunsat.Itisoftenmoreimportanttoconsiderwhatyourcodeexpresses(andhowthisaffectsothersystems)thanhowitexecutes.Nevertheless,itisstillimportanttochoosetherighttoolforthejob,andyoudon'twanttohaveunnecessarilyslowcode.Justbecarefulofover-optimizingwhenitalreadyexecutesfastenough,andaboveall,trytokeepitreadable.

Page 182: ASP.NET Core 1.0 High Performance

ListsA.NETList<T>isastapleofprogramminginC#.It'stypesafe,soyoudon'thavetobotherwithcastingorboxing.Youspecifyyourgenerictypeandcanbesurethatonlyobjectsofthatclass(orprimitive)canbeinyourlist.Listsimplementthestandardlistandenumerableinterfaces(IListandIEnumerable),althoughyougetmoremethodsontheconcretelistimplementation,forexample,addingarange.YoucanalsouseLanguage-IntegratedQuery(LINQ)expressionstoeasilyquerythem,whichistrivialwhenusingfluentlambdafunctions.However,althoughLINQisoftenanelegantsolutiontoaproblem,itcanleadtoperformanceissues,asitisnotalwaysoptimized.

Alistisreallyjustanenhanced,one-dimensional,array.Infact,itusesanarrayinternallytostorethedata.Insomecases,itmaybebettertodirectlyuseanarrayforperformance.Arrayscanoccasionallybeabetterchoice,ifyouknowexactlyhowmuchdatatherewillbe,andyouneedtoiteratethroughitinsideatightloop.Theycanalsobeusefulifyouneedmoredimensions,orplantoconsumeallofthedatainthearray.

Youshouldbecarefulwitharrays;usethemsparinglyandonlyifbenchmarkingshowsaperformanceproblemwheniteratingoveralist.Althoughtheycanbefaster,theyalsomakeparallelprogramminganddistributedarchitecturemoredifficult,whichiswheresignificantperformanceimprovementscanbemade.

Modernhighperformancemeansscalingouttomanycoresandmultiplemachines.Thisiseasierwithanimmutablestatethatdoesn'tchange,whichiseasiertoenforcewithhigherlevelabstractionsthanwitharrays.Forexample,youcanhelpenforcearead-onlylistwithaninterface.

Ifyouareinsertingorremovingalotofitemsinthemiddleofalargelist,thenitmaybebettertousetheLinkedList<T>class.Thishasdifferentperformancecharacteristicstoalist,asitisn'treallyalist–it'smoreofachain.Itmayperformbetterthanalistforsomespecializedcases,but,inmostcommoncases,itwillbeslower.Forexample,accessbyindexisquickwithalist(asitisarraybacked),butslowwithalinkedlist(asyouwillhavetowalkthechain).

Itisnormallybesttoinitiallyfocusonthewhatandwhyofyourcoderatherthanthehow.LINQisverygoodforthis,asyousimplydeclareyourintentions,anddon'tneedtoworryabouttheimplementationdetailsandloops.Itisabadideatooptimizeprematurely,sodothisonlyiftestingshowsaperformanceproblem.Inmostcommoncases,alististhecorrectchoiceunlessyouneedtoselectonlyafewvaluesfromalargeset,inwhichcase,dictionariescanperformbetter.

Page 183: ASP.NET Core 1.0 High Performance

DictionariesDictionariesaresimilartolists,butexcelatquicklyretrievingaspecificvaluewithakey.Internally,theyareimplementedwithahashtable.There'sthelegacyHashtableclass(intheSystem.Collections.NonGenericpackage)butthisisnottypesafe,whereasDictionary<T>isagenerictype,soyouprobablyshouldn'tuseHashtableunlessyou'reportingoldcodeto.NETCore.ThesameappliestoArrayList,whichisthelegacy,non-genericversionofList.

Adictionarycanlookupavaluewithakeyveryquickly,whereasalistwouldneedtogothroughallthevaluesuntilthekeywasfound.Youcan,however,stillenumerateadictionaryasitisordered,althoughthisisn'treallyhowitisintendedtobeused.Ifyoudon'tneedordering,thenyoucanuseaHashSet.Therearesortedversionsofallofthesedatastructures,andyoucanagainuseread-onlyinterfacestomakethemdifficulttomutate.

Page 184: ASP.NET Core 1.0 High Performance

CollectionbenchmarksAccuratebenchmarkingishardandtherearelotsofthingswhichcanskewyourresults.Compilersareverycleverandwilloptimize,whichcanmaketrivialbenchmarkslessvaluable.Thecompilermayoutputverysimilarcodefordifferentimplementations.

Whatyouputinyourdatastructureswillalsohavealargeeffectontheirperformance.It'susuallybesttotestorprofileyouractualapplicationandnotoptimizeprematurely.Readabilityofcodeisveryvaluableandshouldn'tbesacrificedforruntimeefficiencyunlessthereisasignificantperformanceproblem(orifit'salreadyunreadable).

Therearebenchmarkingframeworksthatyoucanusetohelpwithyourtesting,suchasBenchmarkDotNetwhichisavailableatgithub.com/PerfDotNet/BenchmarkDotNet.However,thesecanbeanoverkill,andaresometimestrickytosetup,especiallyon.NETCore.OtheroptionsincludeSimpleSpeedTester(whichyoucanreadmoreaboutattheburningmonk.github.io/SimpleSpeedTester)andMiniBench(availablefromgithub.com/minibench).

We'llperformsomesimplebenchmarkstoshowhowyoumightgoaboutthis.However,don'tassumethattheconclusionsdrawnherewillalwaysholdtrue,sotestforyoursituation.First,wewilldefineasimplefunctiontorunourtests:

privatestaticlongRunTest(Func<double>func,intruns=1000)

{

vars=Stopwatch.StartNew();

for(intj=0;j<runs;j++)

{

func();

}

s.Stop();

returns.ElapsedMilliseconds;

}

WeuseStopwatchhereasusingDateTimecancauseproblems,evenwhenusingUTC,asthetimecouldchangeduringthetestandtheresolutionisn'thighenough.Wealsoneedtoperformmanyrunstogetanaccurateresult.Wethendefineourdatastructurestotestandprepopulatethemwithrandomdata.

varrng=newRandom();

varelements=100000;

varrandomDic=newDictionary<int,double>();

for(inti=0;i<elements;i++)

{

randomDic.Add(i,rng.NextDouble());

}

varrandomList=randomDic.ToList();

varrandomArray=randomList.ToArray();

Wenowhaveanarray,list,anddictionarycontainingthesamesetof100,000key/valuepairs.

Page 185: ASP.NET Core 1.0 High Performance

Next,wecanperformsometestsonthemtoseewhatstructureperformsbestinvarioussituations.

varafems=RunTest(()=>

{

varsum=0d;

foreach(varelementinrandomArray)

{

sum+=element.Value;

}

returnsum;

},runs);

Theprecedingcodetimeshowlongittakestoiterateoveranarrayinaforeachloopandsumsupthedoubleprecisionfloatingpointvalues.Wecanthencomparethistootherstructuresandthedifferentwaysofaccessingthem.Forexample,iteratingadictionaryinaforloopisdoneasfollows:

vardfms=RunTest(()=>

{

varsum=0d;

for(inti=0;i<randomDic.Count;i++)

{

sum+=randomDic[i];

}

returnsum;

},runs);

Thisperformsverybadly,asitisnothowdictionariesaresupposedtobeused.Dictionariesexcelatextractingarecordbyitskeyveryquickly.Soquicklyinfactthatyouwillneedtorunthetestmanymoretimestogetarealisticvalue.

varlastKey=randomList.Last().Key;

vardsms=RunTest(()=>

{

doubleresult;

if(randomDic.TryGetValue(lastKey,outresult))

{

returnresult;

}

return0d;

},runs*10000);

Console.WriteLine($"Dictselect{(double)dsms/10000}ms");

GettingavaluefromadictionarywithTryGetValueisextremelyquick.Youneedtopassthevariabletobesetintothemethodasanoutparameter.YoucanseeifthiswassuccessfulandiftheitemwasinthedictionarybytestingtheBooleanvaluereturnedbythemethod.

Conversely,addingitemstoadictionaryonebyonecanbeslow,soitalldependsonwhatyou'reoptimizingfor.Thefollowingimageshowstheoutputofaverysimpleconsoleapplicationthattestsvariouscombinatorialpermutationsofdatastructuresandtheiruses:

Page 186: ASP.NET Core 1.0 High Performance

Theseresults,shownintheprecedingimage,areinformative,butyoushouldbeskeptical,asmanythingscanskewtheoutput,forexample,theorderingofthetests.Ifthegapissmall,thenthereisprobablynotmuchtochoosebetweentwovariants,butyoucanclearlyseethebigdifferences.

Tip

Togetmorerealisticresults,besuretocompileinreleasemodeandrunwithoutdebugging.Theabsoluteresultswilldependonyourmachineandarchitecture,buttherelativemeasuresshouldbeusefulforcomparisons.Youmaygethigherperformanceifcompilingtoasingleexecutablebinarywiththe.NETnativetoolchainorwithadifferentreleaseofthe.NETCoreframework.

Themainlessonhereistomeasureforyourspecificapplicationandchoosethemostappropriatedatastructurefortheworkthatyouareperforming.Thecollectionsinthestandardlibraryshouldserveyouwellformostpurposes,andthereareothersthatarenotcoveredhere,whichcansometimesbeuseful,suchasaQueueorStack.

Youcanfindmoreinformationaboutthebuilt-incollectionsanddatastructuresonMSDN(msdn.microsoft.com/en-us/library/system.collections.generic).Youcanalsoreadaboutthemonthe.NETCoredocumentationsiteontheGitHubpages(dotnet.github.io/docs/essentials/collections/Collections-and-Data-Structures.html).

However,therearesomerarerdatastructures,notinthestandardcollection,thatyoumayoccasionallywishtouse.We'llshowanexampleofoneofthesenow.

Page 187: ASP.NET Core 1.0 High Performance

BloomfiltersBloomfiltersareaninterestingdatastructurethatcanincreaseperformanceforcertainusecases.Theyusemultipleoverlaidhashingfunctionsandcanquicklytellyouifanitemdefinitelydoesnotexistinaset.However,theycan'tsaywithcertaintyifanitemexists,onlythatitislikelyto.Theyareusefulasapre-filter,sothatyoucanavoidperformingalookup,becauseyouknowforsurethattheitemwon'tbethere.

ThefollowingimageshowshowaBloomfilterworks.A,B,andChavebeenhashedandinsertedintothefilter.Dishashedtocheckifitisinthefilterbut,asitmapstoazerobit,weknowthatitisnotinthere.

Bloomfiltersaremuchsmallerthanholdingallthedataorevenalistofhashesforeachitemintheset.Theycanalsobemuchquicker,asthelookuptimeisconstantforanysizeofset.Thisconstanttimecanbelowerthanthetimetolookupaniteminalargelistordictionary,especially

Page 188: ASP.NET Core 1.0 High Performance

ifitisonthefilesystemorinaremotedatabase.

AnexampleapplicationforaBloomfiltercouldbealocalDNSserver,whichhasalistofdomainstooverride,butforwardsmostrequeststoanupstreamserver.Ifthelistofcustomdomainsislarge,thenitmaybeadvantageoustocreateaBloomfilterfromtheentriesandholdthisinmemory.

Whenarequestcomesin,itischeckedagainstthefilter,andifitdoesn'texist,thentherequestisforwardedtotheupstreamserver.Iftheentrydoesexistinthefilter,thenthelocalhostsfileisconsulted;iftheentryisthere,itsvalueisused.Thereisasmallchancethattheentrywillnotbeinthelist,evenifthefilterthinksitis.Inthiscase,whenitisn'tfound,therequestisforwarded,butthisapproachstillavoidstheneedtoconsultthelistforeveryrequest.

AnotherexampleofusingaBloomfilterisinacachingnode,perhapsaspartofaproxyorCDN.Youwouldn'twanttocacheresourcesthatareonlyrequestedonce,buthowcanyoutellwhenthesecondrequestoccursifyouhaven'tcachedit?IfyouaddtherequesttoaBloomfilter,youcaneasilytellwhenthesecondrequestoccursandthencachetheresource.

TheyarealsousedinsomedatabasestoavoidexpensivediskoperationsandinCacheDigests,whichallowanagenttodeclarethecontentsofitscache.HTTP/2maysupportCacheDigestsinthefuture,butthiswillprobablyuseGolomb-codedsets(GCS),whicharesimilartoBloomfilters,butsmaller,attheexpenseofslowerqueries.

ThereisanopensourceimplementationofaBloomfilterin.NETavailableatbloomfilter.codeplex.comamongothers.Youshouldtesttheperformanceforyourselftomakesuretheyofferanimprovement.

Page 189: ASP.NET Core 1.0 High Performance

HashingandchecksumsHashingisanimportantconcept,whichisoftenusedtoensuredataintegrityorlookupvaluesquicklyandsoitisoptimizedtobefast.Thisiswhygeneralhashingfunctionsshouldnotbeusedontheirowntosecurelystorepasswords.Ifthealgorithmisquick,thenthepasswordcanbeguessedinareasonablyshortamountoftime.Hashingalgorithmsvaryintheircomplexity,speedofexecution,outputlength,andcollisionrate.

Averybasicerrordetectionalgorithmiscalledaparitycheck.Thisaddsasinglebittoablockofdataandisrarelyuseddirectlyinprogramming.Itis,however,extensivelyusedatthehardwarelevel,asitisveryquick.Yet,itmaymissmanyerrorswherethereareanevennumberofcorruptions.

ACyclicRedundancyCheck(CRC)isaslightlymorecomplexerrordetectingalgorithm.TheCRC-32(alsowrittenCRC32)versioniscommonlyusedinsoftware,particularlyincompressionformats,asachecksum.

Tip

Youmaybefamiliarwiththebuilt-insupportforhashcodesin.NET(withtheGetHashCodemethodonallobjects),butyoushouldbeverycarefulwiththis.Theonlyfunctionofthismethodistoassistwithpickingbucketsindatastructuresthatusehashtablesinternally,suchasadictionary,andalsoinsomeLINQoperations.Itisnotsuitableasachecksumorkey,becauseitisnotcryptographicallysecureanditvariesacrossframeworks,processes,andtime.

YoumayhaveusedtheMessageDigest5(MD5)algorithminthepast,buttodayitsuseisstronglydiscouraged.ThesecurityofMD5isheavilycompromisedandcollisionscanbeproducedeasily.Sinceitisveryquick,itmayhavesomenon-secureuses,suchasnon-maliciouserrorcheckingbuttherearebetteralgorithmsthatarefastenough.

Ifyouneedastrongbutquickhashingfunction,thentheSecureHashAlgorithm(SHA)familyisagoodchoice.However,SHA-1isnotconsideredfutureproof,soforanewcode,SHA-256isgenerallyabetterchoice.

Whensigningmessages,youshoulduseadedicatedMessageAuthenticationCode(MAC),suchasaHash-basedMAC(HMAC),whichavoidsvulnerabilitiesinasinglepassofthehashingfunction.AgoodoptionistheHMACSHA256classbuiltinto.NET.VariousAPIs,suchassomeoftheAWSRESTAPIs,useHMAC-SHA256toauthenticaterequests.Thisensuresthat,eveniftherequestisperformedoveranunencryptedHTTPchannel,theAPIkeycan'tbeinterceptedandrecovered.

AsbrieflymentionedinChapter1,WhyPerformanceIsaFeature,passwordhashingisaspecialcaseandgeneralpurposehashingalgorithmsarenotsuitableforit–theyaretoofast.AgoodchoiceisPassword-BasedKeyDerivationFunction2(PBKDF2),whichweusedasanexampleinChapter2,MeasuringPerformanceBottlenecks.PBKDF2isaparticularlypopular

Page 190: ASP.NET Core 1.0 High Performance

choicefor.NET,asitisbuiltintotheframework,andso,theimplementationismorelikelytobecorrect.IthasbeenbuiltagainstanRFCandreviewedbyMicrosoft,whichyoucan'tsayforanyrandompieceofcodefoundonline.Forexample,youcoulddownloadanimplementationofbcryptfor.NET,butyouhavetotrustthatitwascodedcorrectlyorverifyityourself.

Page 191: ASP.NET Core 1.0 High Performance

HashingbenchmarksLet'sdosomesimplebenchmarkingofvarioushashfunctionstoseehowtheycompareperformancewise.Inthefollowingcodesnippet,wedefineamethodforrunningourtests,similartotheoneforthepreviouscollectionbenchmarks,buttakinganActionparameter,ratherthanaFunc<double>,aswedon'twanttoreturnavalue:

privatestaticlongRunTest(Actionfunc,intruns=1000)

{

vars=Stopwatch.StartNew();

for(intj=0;j<runs;j++)

{

func();

}

s.Stop();

returns.ElapsedMilliseconds;

}

Weincludethefollowingusingstatement:

usingSystem.Security.Cryptography;

Next,wedefineashortprivateconstantstring(hashingData)tohashintheclassandgetthebytesforitinan8-bitUnicode(UTF8)format.

varsmallBytes=Encoding.UTF8.GetBytes(hashingData);

Wealsowanttogetalargerblockofbytestohashtoseehowitcomparesperformancewise.Forthis,weuseacryptographicallysecurerandomnumbergenerator.

varlargeBytes=newbyte[smallBytes.Length*100];

varrng=RandomNumberGenerator.Create();

rng.GetBytes(largeBytes);

Weneedakeyforsomeofourfunctions,soweusethesametechniquetogeneratethis.

varkey=newbyte[256];

varrng=RandomNumberGenerator.Create();

rng.GetBytes(key);

Next,wecreateasortedlistofthealgorithmstotestandexecutethetestsforeachone:

varalgos=newSortedList<string,HashAlgorithm>

{

{"1.MD5",MD5.Create()},

{"2.SHA-1",SHA1.Create()},

{"3.SHA-256",SHA256.Create()},

{"4.HMACSHA-1",newHMACSHA1(key)},

{"5.HMACSHA-256",newHMACSHA256(key)},

};

foreach(varalgoinalgos)

{

HashAlgorithmTest(algo);

Page 192: ASP.NET Core 1.0 High Performance

}

Ourtestmethodrunsthefollowingtestsoneachalgorithm.TheyallinheritfromHashAlgorithm,sowecanruntheComputeHashmethodoneachofthemforthesmallandlargebytearrays.

varsmallTimeMs=RunTest(()=>

{

algo.Value.ComputeHash(smallBytes);

},runs);

varlargeTimeMs=RunTest(()=>

{

algo.Value.ComputeHash(largeBytes);

},runs);

Wethencalculatetheaverage(mean)timeforbothsizes.Wecastthelongintegertoadoubleprecisionfloatingpointnumbersothatwecanrepresentsmallvaluesbetweenoneandzero.

varavgSmallTimeMs=(double)smallTimeMs/runs;

varavgLargeTimeMS=(double)largeTimeMs/runs;

Theprecedingmethodthenoutputsthesemeantimestotheconsole.WeneedtotestPBKDF2separately,asitdoesn'tinheritfromHashAlgorithm.

varslowRuns=10;

varpbkdf2=newRfc2898DeriveBytes(hashingData,key,10000);

varpbkdf2Ms=RunTest(()=>

{

pbkdf2.GetBytes(256);

},slowRuns);

PBKDF2issoslowthatitwouldtakeaconsiderableamountoftimetoperform100,000runs(thisisthepointofusingit).Internally,thisRFC2898implementationofthekey-stretchingalgorithmrunsHMACSHA-110,000times.Thedefaultis1,000,butduetothecomputingpoweravailabletoday,itisrecommendedtosetthistoatleastanorderofmagnitudehigher.Forexample,Wi-FiProtectedAccessII(WPA2)uses4,096roundsofiterationstoproducea256-bitkeywiththeServiceSetIdentifier(SSID)asthesalt.

Theoutputwilllooksomethinglikethefollowing:

Page 193: ASP.NET Core 1.0 High Performance

Fromtheprecedingoutput,youcanseethatthetimetakenforonehashvariesfromabout720nanosecondsforasmallMD5to32microsecondsforalargeHMACSHA-256and125millisecondsforasmallPBKDF2withtypicalparameters.

Benchmarkingresultscanvarydramatically,soyoushouldn'treadtoomuchintoabsolutevalues.Forexample,theoutputfromtheBenchmarkDotNettoolcomparingMD5andSHA-256onthesamemachinelookslikethis:

Youcanseeinthelastimagethattheresultsaredifferenttoourhomemadebenchmark.However,thisusesthefull.NETFramework,calculatesmedianratherthanmeanfortheaveragetime,andrunsindebugmode(whichithelpfullywarnsusof)amongotherthings.

Afastermachinewillhaveahigherthroughput(ascanbeseenintheBenchmarkDotNetREADME.mdonGitHub).DedicatedhardwaresuchasGraphicsProcessingUnits(GPUs),Field-

Page 194: ASP.NET Core 1.0 High Performance

ProgrammableGateArrays(FPGAs),andApplication-SpecificIntegratedCircuits(ASICs)canbemuchfaster.Thesetendtobeusedintheminingofbitcoin(andothercryptocurrencies),asthesearebasedonhashingasaproof-of-work.BitcoinusesSHA-256,butothercurrenciesusedifferenthashingalgorithms.

ThesamealgorithmsformthebasisofTLS,sofasterhardwarecanhandleagreaternumberofsecureconnections.Asanotherexample,GooglebuiltacustomASICcalledaTensorProcessingUnit(TPU)toacceleratetheirmachinelearningcloudservices.

OtherbenchmarkingsamplesareavailableinBenchmarkDotNet,andwhenyoufirstrunit,youwillbepresentedwiththefollowingmenu:

Thepreviousbenchmarkwasthesecondoption,(number#1Algo_Md5VsSha256).

Benchmarkingishard,soit'sagoodideatousealibrarysuchasBenchmarkDotNetifyoucan.TheonlyconclusionwecandrawfromourbenchmarksisthatSHA-256isslowerthanMD5.

Page 195: ASP.NET Core 1.0 High Performance

However,SHA-256shouldbefastenoughformostapplicationsandit'smoresecureforintegritychecking.However,itisstillnotsuitableforpasswordstorage.

SHA-256canbeusedtoprovidesignaturesforverifyingdownloadedfiles,whichmustberetrievedoverHTTPStobesafe,andforsigningcertificates.WhenusedaspartofanHMAC,itcanalsobeusedtosecurelyauthenticatemessages–APIrequests,forexample.YouwillonlyconnectsuccessfullyifyouknowthecorrectAPIkeytohashwith.

Page 196: ASP.NET Core 1.0 High Performance

SerializationSerializationistheprocessofturningobjectsintodatasuitablefortransmissionoveranetworkorforstorage.Wealsoincludedeserialization,whichisthereverse,underthisumbrella.Serializationcanhavesignificantperformanceimplications,notonlyonthenetworktransmissionspeedbutalsooncomputation,asitcanmakeupmostoftheexpensiveprocessingonawebserver.YoucanreadmoreaboutserializationonMSDN(msdn.microsoft.com/en-us/library/mt656716).

Serializationformatscanbetext-basedorbinary.Somepopulartext-basedformatsareExtensibleMarkupLanguage(XML)andJavaScriptObjectNotation(JSON).ApopularbinaryformatisProtocolBuffers,whichwasdevelopedatGoogle.There'sanotherbinaryserializationformat(BinaryFormatter)builtintothefull.NET,butthisisnotin.NETCore.

XMLhasfallenoutoffashionwithdevelopers,andJSONisnowgenerallypreferred.ThisispartlyduetothesmallersizeofequivalentJSONpayloads,butitmayalsobeduetotheuseofXMLintheoriginallynamedSimpleObjectAccessProtocol(SOAP).ThisisusedinWindowsCommunicationFoundation(WCF),butSOAPisnolongeranacronym,asdevelopersdiscovereditisfarfromsimple.

JSONispopularduetobeingcompact,human-readable,andbecauseitcaneasilybeconsumedbyJavaScript,particularlyinwebbrowsers.TherearemanydifferentJSONserializersfor.NET,withdifferentperformancecharacteristics.However,becauseJSONisnotasrigidlydefinedasXML,therecanbedifferencesinimplementations,whichmakethemincompatible,especiallywhendealingwithcomplextypessuchasdates.Forexample,theverypopularJson.NETrepresentsdatesintheInternationalOrganizationforStandardization(ISO)format,whereastheJSONserializerusedinoldversionsofASP.NETMVCrepresenteddatesasthenumberofmillisecondssincetheUnixepoch,wrappedinaJavaScriptdateconstructor.

The.NETdevelopercommunityhasconvergedonJson.NET,andcompatibilityisalwayspreferabletoperformance.ASP.NETWebAPIhasusedJson.NETasthedefaultforawhilenow,andASP.NETCorealsousesJson.NET.Thereisaserializerthat'spartoftheServiceStackframeworkcalledServiceStack.Text,whichclaimstobefaster,butyoushouldprobablyvaluecompatibilityanddocumentationoverspeed.ThesameappliestootherJSONlibrariessuchasJil(github.com/kevin-montrose/Jil)andNetJSON(github.com/rpgmaker/NetJSON),whichcanbeevenfasterthanServiceStackinbenchmarks.

Ifyouareafterpureperformance,andyoucontrolalloftheendpoints,thenyouprobablywouldwanttouseabinaryprotocol.However,thismaylimitfutureinteroperabilitywiththird-partyendpointswhichyoudon'tcontrol.Therefore,it'sbesttoonlyusetheseinternally.

ItwouldbeabadideatobuildyourowncustommessageprotocolontopofUDP.So,ifyouwanttousebinaryserialization,youshouldlookatsomethinglikeprotobuf-net,whichisaProtocolBuffersimplementationfor.NET.YoumayalsowishtoconsiderMicrosoft'sBondframework

Page 197: ASP.NET Core 1.0 High Performance

(github.com/Microsoft/bond)orAmazon'sIon(amznlabs.github.io/ion-docs).Youmayneedtotunethesetoolsforbestperformance,forexample,bychangingthedefaultbuffersize.

Page 198: ASP.NET Core 1.0 High Performance

SIMDCPUinstructionsSingleInstructionMultipleData(SIMD)isatechniquethatisavailableonmanymodernprocessorsandcanspeedupexecutionbyparallelizingcalculationseveninasinglethreadononecore.SIMDtakesadvantageofadditionalinstructionsavailableonCPUstooperateonsetsofvalues(vectors)ratherthanjustsinglevalues(scalars).

ThemostcommoninstructionsetforthisiscalledStreamingSIMDExtensions2(SSE2)andithasbeenaroundforover15yearssinceitsdebutwiththePentium4.AnewerinstructionsetcalledAdvancedVectorExtensions(AVX)offerssuperiorperformanceoverSSE2andhasbeenaroundforoverfiveyears.So,ifyou'reusingareasonablyrecentx86-64CPU,thenyoushouldhaveaccesstotheseextrainstructions.

Note

SomeARMCPUs(suchasthoseintheRaspberryPi2and3)containasimilartechnologycalledNEON,officiallyknownasAdvancedSIMD.Thisisnotcurrentlysupportedin.NET,butmaybeinthefuture.AnofficialopensourcelibraryprojectinCishostedatprojectne10.org.

YoucanusethefollowingBooleanpropertytotestifSIMDissupported:

Vector.IsHardwareAccelerated

ThispropertyisJITintrinsic,andthevalueissetbyRyuJITatruntime.

YoucaninstantiateagenerictypedVectororuseoneofthetwo/three/fourdimensionalconvenienceclasses.Forexample,tocreateasingleprecisionfloatingpointvector,youcouldusethefollowinggenericcode:

varvectorf=newVector<float>(11f);

Tocreateasingleprecisionfloatingpoint3Dvectorinstead,youcouldusethiscode:

varvector3d=newVector3(0f,1f,2f);

Tip

AtwodimensionaldoubleprecisionfloatingpointvectorcanbeagoodsubstituteforaComplexstructure.Itwillgivehigherperformanceonhardwareacceleratedsystems.Vector2onlysupportssingleprecisionfloatingpointnumbers,butyoucanusethegenerictypetospecifytherealandimaginarycomponentsofthecomplexnumberasadouble.Complexonlysupportsdoubleprecisionfloatingpointnumbers,but,ifyoudon'tneedhighprecision,youcouldstillusetheVector2convenienceclass.Unfortunately,thismeansthatit'snotsimplyadropinreplacement,butthemathisdifferentanyway.

Youcannowusestandardvectormathematics,butmodifyingyouralgorithmstotakeadvantageofvectorscanbecomplexandisn'tsomethingyoushouldtypicallybedoinginawebapplication.It

Page 199: ASP.NET Core 1.0 High Performance

canbeusefulfordesktopapplications,but,ifaprocesstakesalongtimeinawebrequest,it'softenbesttorunitinthebackgroundandthenitdoesn'tneedtobeasquick.

Wewillcoverthisdistributedarchitectureapproachinthenextchapter.Forthisreason,wewon'tbegoingintoanymoredetailonSIMD,butyoucanreadmoreonitifyouwish,nowthatyouhaveatasteofit.Youcanreadsomebackgroundinformationatwikipedia.org/wiki/SIMDandyoucanfindthedocumentationforthe.NETimplementationonMSDNatmsdn.microsoft.com/en-us/library/dn858218.Youcouldalsotakealookattheexampleconsoleapplication,whichisavailablefordownloadalongwiththisbook,asasimplestarterforten.

Page 200: ASP.NET Core 1.0 High Performance

ParallelprogrammingWhileSIMDisgoodatincreasingtheperformanceofasinglethreadrunningononecore,itdoesn'tworkacrossmultiplecoresorprocessorsanditsapplicationsarelimited.ModernscalingmeansaddingmoreCPUs,notsimplymakingasinglethreadfaster.Wedon'tjustwanttoparallelizeourdataasSIMDdoes;weshouldactuallyfocusmoreonparallelizingourprocessing,asthiscanscalebetter.

Therearevarious.NETtechnologiesavailabletohelpwithparallelprocessingsothatyoudon'thavetowriteyourownthreadingcode.TwosuchparallelextensionsareParallelLINQ(PLINQ),whichextendstheLINQoperationsyou'refamiliarwith,andtheTaskParallelLibrary(TPL).

Page 201: ASP.NET Core 1.0 High Performance

TaskParallelLibraryOneofthemainfeaturesoftheTPListoextendloopstoruninparallel.However,youneedtobecarefulwithparallelprocessing,asitcanactuallymakeyoursoftwareslowerwhiledoingsimpletasks.Theoverheadsinvolvedwithmarshallingthemultipletaskscandwarftheexecutionoftheworkloadfortrivialoperations.

Forexample,takethefollowingsimpleforloop:

for(inti=0;i<array.Length;i++)

{

sum+=array[i];

}

Thearrayintheprecedingforloopcontains100,000integers,butaddingintegersisoneoftheeasiestthingsaCPUcandoandusingaforlooponanarrayisaveryquickwayofenumerating.Thisaccumulationwillcompleteinunderatenthofamillisecondonareasonablymodernmachine.

Youmaythinkthatyouwouldbeabletospeedthisupbyparallelizingtheoperation.Perhapsyoucouldsplitthearray,runthesummationontwocoresinparallelandaddtheresults.

Youmightusethefollowingcodetoattemptthis:

Parallel.For(0,array.Length,i=>

{

Interlocked.Add(refsum,array[i]);

});

Tip

Youmustuseaninterlockedaddoryouwillgetanincorrectsummationresult.Ifyoudon't,thethreadswillinterferewitheachother,corruptingthedatawhenwritingtothesamelocationinmemory.

However,thiscodeactuallyrunsover42timesslowerthanthefirstexample.Theextraoverhead,complexityofrunningmanythreads,andlockingthevariablesothatonlyonethreadcanwritetoitatatimeisjustnotworthitinthiscase.

Parallelizationcanbeusefulformorecomplexprocesses,especiallyifthebodyoftheloopperformssomeslowoperationsuchasaccessingthefilesystem.However,blockingI/Ooperationsmaybebetterdealtwithbyusingasynchronousaccess.Parallelaccesscancausecontention,becauseaccessmayeventuallyhavetobeperformedinseriesatsomepoint,forexample,atthehardwarelevel.

Ifwewanttoperformamoreprocessor-intensiveoperation,suchashashingmultiplepasswords,thenrunningthetasksinparallelcanbebeneficial.ThefollowingcodeperformsaPBKDF2hashoneachpasswordinalistandthencalculatestheBase64representationoftheresult:

Page 202: ASP.NET Core 1.0 High Performance

foreach(varpasswordinpasswords)

{

varpbkdf2=newRfc2898DeriveBytes(password,256,10000);

Convert.ToBase64String(pbkdf2.GetBytes(256));

}

We'renotusingtheoutputinthisexample,butyoumaybedoingthistoupgradethesecurityofthepasswordsinyourdatabasebymigratingthemtoamoreresilientkey-stretchingalgorithm.Theinputmaybeplaintextpasswordsortheoutputofalegacyone-wayhashfunction,forexampleMD5oranunsaltedSHA.

WecanimprovethespeedofthisonamulticoresystembyusingtheParallel.ForEachloop,usingcodesuchasthefollowing:

Parallel.ForEach(passwords,password=>

{

varpbkdf2=newRfc2898DeriveBytes(password,256,10000);

Convert.ToBase64String(pbkdf2.GetBytes(256));

});

Thiswillspeeduptheprocess,butbyhowmuchwilldependonmanyfactors,suchasthenumberofpasswordsinthelist,thenumberoflogicalprocessorsandthenumberofCPUcores.Forexample,onaCorei5CPUwithtwocores,butfourlogicalprocessors,havingonlytwopasswordsinthelistdoesnotresultinamassiveimprovement(only1.5timesquicker).Withfourpasswords(ormore)inthelist,theimprovementisbetter(about1.9timesquicker).Thereisstillsomeoverhead,soyoucan'tgetdoublethespeedwithtwicetheCPUcores.

WecanseethereasonforthisdifferencebylookingattheCPUutilizationinthetaskmanagerduringbenchmarking.Withonlytwopasswordstohash,theCPUgraphlookslikethefollowing:

Page 203: ASP.NET Core 1.0 High Performance

Intheprecedinggraph,wecanseethatinitially,whenhashinginseries,theCPUisrunningatabout25%,fullyusingonelogicalCPU.Whenhashingtwopasswordsinparallel,ituses50%,runningontwologicalprocessors.Thisdoesn'ttranslateintoatwofoldincreaseinspeedduetotheintrinsicoverheadsandthenatureofhyper-threading.

Note

Hyper-threadingisatechnologythattypicallyexposestwologicalprocessorstotheOSforeach

Page 204: ASP.NET Core 1.0 High Performance

physicalcore.However,thetwologicalCPUsstillsharetheexecutionresourcesoftheirsinglecore.

AlthoughtherearetwocoresontheCPUdie,hyper-threadingexposesfourlogicalCPUstotheOS.Asweonlyhavetwothreads,becausewearehashingtwopasswords,wecanonlyusetwoprocessors.Ifthethreadsareexecutedondifferentcores,thenthespeedincreasecanbegood.Butiftheyareexecutedonprocessorssharingthesamecore,thenperformancewon'tbeasimpressive.Itisstillbetterthansingle-threadedhashingduetoschedulingimprovements,whichiswhathyper-threadingisdesignedfor.

Whenwehashfourpasswordsatthesametime,theCPUgraphlookslikethefollowing:

Page 205: ASP.NET Core 1.0 High Performance

Wecanseethatnowtheinitial25%usagejumpstoalmostfullutilizationandwearemakinguseofmostoftheprocessor.Thistranslatestojustunderadoublingoftheperformanceascomparedtohashinginsequence.Therearestillsignificantoverheadsinvolved,but,asthemainoperationisnowsomuchquicker,thetradeoffisworthit.

Page 206: ASP.NET Core 1.0 High Performance

ParallelLINQThereareotherwaystotakeadvantageofparallelprogramming,suchasLINQexpressions.WecouldrewritethepreviousexampleasaLINQexpressionanditmaylooksomethinglikethefollowing:

passwords.AsParallel().ForAll(p=>

{

varpbkdf2=newRfc2898DeriveBytes(p,256,10000);

Convert.ToBase64String(pbkdf2.GetBytes(256));

});

YoucanenablethesefeatureswiththeAsParallel()method.TheForAll()methodhasthesamepurposeastheloopsinpreviousexamplesandisusefuliftheorderisunimportant.Iforderingisimportant,thenthereisanAsOrdered()method,whichcanhelpsolvethis.However,thiscanreducetheperformancegainsduetotheextraprocessinginvolved.

Thisexampleperformssimilarlytothepreviousonethatusedaparallelloop,whichisunsurprising.Wecanalsolimitthenumberofoperationsthatcanoccurinparallel,usingtheWithDegreeOfParallelism()methodasfollows:

passwords.AsParallel().WithDegreeOfParallelism(2).ForAll(p=>

{

varpbkdf2=newRfc2898DeriveBytes(p,256,10000);

Convert.ToBase64String(pbkdf2.GetBytes(256));

});

Thisprecedingexamplelimitsthehashestotwoatatimeandperformssimilarlytowhenweonlyhadtwopasswordsinthelist,whichistobeexpected.Thiscanbeusefulifyoudon'twanttomaxouttheCPU,becausethereareotherimportantprocessesrunningonit.

YoucanachievethesameeffectwiththeTPLbysettingtheMaxDegreeOfParallelismpropertyonaninstanceoftheParallelOptionsclass.Thisobjectcanthenbepassedintooverloadedversionsoftheloopmethodsasaparameter,alongwiththemainbody.

Tip

It'simportant,whenyou'reusingparallelLINQtoquerydatasets,thatyoudon'tlosesightofthebestplaceforthequerytobeperformed.Youmayspeedupaqueryintheapplicationwithparallelization,butthebestplaceforthequerytooccurmaystillbeinthedatabase,whichcanbeevenfaster.Toreadmoreonthistopic,referbacktoChapter5,OptimizingI/OPerformance,andChapter3,FixingCommonPerformanceProblems.

Page 207: ASP.NET Core 1.0 High Performance

ParallelbenchmarkingLet'shavealookattheoutputofasimple.NETCoreconsoleapplication,whichbenchmarksthetechniquesthatwehavejustdiscussed.Itshowsonesituationwhereparallelizationdoesn'thelpandactuallymakesthingsworse.Itthenshowsanothersituationwhereitdoeshelp.

Whencalculatingasum,byaccumulating100,000randomintegersbetweenzeroandten,thequickestwayistouseanarrayinasimpleforeachloop.Usingparallelizationheremakestheprocessmuchslower,andifusedNaïvely,withoutlocking,willgiveanincorrectresult,whichismuchworse.

Whenperformingamorecomputationallyintensiveworkload,suchasaPBKDF2hashing

Page 208: ASP.NET Core 1.0 High Performance

functiononmultiplepasswords,parallelizationcanhelpsignificantly.Thetimeisalmosthalved,asitisrunningacrosstwocores.Thefinaloperation,whichlimitsthenumberofthreads,cantakeavaryingamountoftimeondifferentruns.Thisislikelyduetothethreadssometimessharingacoreandsometimesrunningondifferentcores.Itcanbealmostasquickasusingalllogicalcores,dependingonthework.

TheCPUgraphforthebenchmarklookslikethefollowing:

Page 209: ASP.NET Core 1.0 High Performance

TheinitialparallelsummationsmaxouttheCPUandareveryinefficient.Next,thesingle-threadedhashingusesonlyonelogicalprocessor(25%),buttheother,laterhashesmakealmostfulluseofboththecores.Thefinalhashing,limitedtotwopasswordsatatime,onlymakesuseofhalftheCPUpower.

Page 210: ASP.NET Core 1.0 High Performance

ParallelprogramminglimitationsPerformanceproblemswithwebapplicationsdon'ttypicallymeanincreasingspeedforasingleuseronthesysteminisolation.It'seasytomakeawebappperformwhenthere'sonlyoneuser,butthechallengeliesinmaintainingthatsingleuserperformanceasthenumberofusersscalesupandyouhavewall-to-wallrequests.

Theparallelprogrammingtechniquesdiscussedinthissectionhavelimiteduseinscalingwebapplications.Youalreadyhaveaparallelizedsystem,aseachuserrequestwillbeallocateditsownresources.Youcansimplyaddmoreinstances,agents,ormachinestomeetdemand.Theproblemthenisindistributingworkefficientlybetweenthemandavoidingbottlenecksforsharedresources.We'llcoverthismoreinthenextchapter,butfirstlet'slookatsomethingsthatyoushouldbeavoiding.

Page 211: ASP.NET Core 1.0 High Performance

PracticestoavoidWe'veshownsomewaysofspeedingupsoftware,butit'softenbettertoillustratewhatnottodoandhowthingscangowrong.Webapplicationsgenerallyperformwellifnobadpracticeshavebeenfollowedandherewe'llhighlightafewthingsyoushouldwatchoutfor.

Page 212: ASP.NET Core 1.0 High Performance

ReflectionReflectionistheprocessofprogrammaticallyinspectingyourcodewithothercode,anddiggingintoitsinternalsatruntime.Forexample,youcouldinspectanassemblywhenitisloadedtoseewhatclassesandinterfacesitimplementssothatyoucancallthem.Itisgenerallydiscouragedandshouldbeavoidedifpossible.Thereareusuallyotherwaystoachievethesameresultthatdon'trequirereflection,althoughitisoccasionallyuseful.

Reflectionisoftenbadforperformance,andthisiswell-documented,but,asusual,itdependsonwhatyou'reusingitfor.Whatisnewisthattherearesignificantchangestoreflectionfor.NETCore.TheAPIhaschangedanditisnowoptional.So,ifyoudon'tusereflection,youdon'thavetopaytheperformancepenalty.Thisallowsthenativetoolchaintooptimizecompilationbetter,asreflectionaddsrestrictionstowhatcanbedonewithstaticlinking.

ThereisanextramethodonthereflectionAPInow,so,whereaspreviouslyyouwouldhavecalledsomethinglikemyObject.GetType().GetMembers(),younowneedtocallitasmyObject.GetType().GetTypeInfo().GetMembers()byinsertingthenewGetTypeInfo()method,whichisintheSystem.Reflectionnamespace.

Ifyoumustusereflection,thenitisbestnottoperformitrepeatedlyorinatightloop.However,itwouldbefinetouseitonceduringthestartupofyourapplication.Yet,ifyoucanavoidusingitentirely,youcanbenefitfromsomeofthenewimprovementsin.NETCore,forexample,nativecompilationandtheperformanceboostthatitbrings.

Page 213: ASP.NET Core 1.0 High Performance

RegularexpressionsAregularexpression(regex)canbeveryuseful,butcanperformbadlyandistypicallymisusedinsituationswhereanothersolutionwouldbebetter.Forexample,aregexisoftenusedfore-mailvalidationwhentherearemuchmorereliablewaystodothis.

Ifreusingaregexrepeatedly,youmaybebetteroffcompilingitforperformancebyspecifyingtheRegexOptions.Compiledoptionintheconstructor.Thisonlyhelpsifyou'reusingtheregexalotandinvolvesaninitialperformancepenalty.So,ensurethatyoucheckifthereisactuallyanimprovementanditisn'tnowslower.

TheRegexOptions.IgnoreCaseoptioncanalsoaffectperformance,butitmayinfactslowthingsdown,soalwaystestforyourinputs.CompilinghasaneffectonthistooandyoumaywanttouseRegexOptions.CultureInvariantinaddition,toavoidcomparisonissues.

Bewaryoftrustinguserinputtoaregex.Itispossibletogetthemtoperformalargeamountofbacktrackinganduseexcessiveresources.Youshouldn'tallowunconstrainedinputtoaregex,astheycanbemadetorunforhours.

Regexesareoftenusedfore-mailaddressvalidation,butthisisusuallyabadidea.Theonlywaytofullyvalidateane-mailaddressistosendane-mailtoit.Youcanthenhavetheuserclickalinkinthee-mailtoindicatethattheyhaveaccesstothatmailboxandhavereceivedit.E-mailaddressescanvaryalotfromthecommononesthatpeopleareregularlyexposedto,andthisiseventruerwiththenewtop-leveldomainsbeingadded.

Manyoftheregexesfore-mailaddressvalidationfoundonlinewillrejectperfectlyvalide-mailaddresses.Ifyouwanttoassisttheuser,andperformsomebasice-mailaddressvalidationonaform,thenallyoucansensiblydoischeckthatthereisan@symbolinit(anda.afterthat)sothatthee-mailisintheformx@y.z.Youcandothiswithasimplestringtestandavoidtheperformancepenaltyandsecurityriskofaregularexpression.

Page 214: ASP.NET Core 1.0 High Performance

StringconcatenationintightloopsAsstringsareimmutableandcan'tchange,whenyouconcatenateastring,anewobjectiscreated.Thiscancauseperformanceproblemsandissueswithmemoryuseifyoudoitalotinsideatightloop.

Youmayfinditbettertouseastringbuilderoranotherapproach.However,don'tfrettoomuchaboutthis,asitonlyappliesatalargescale.Alwaystesttoseeifitisgenuinelyaproblemanddon'tmicro-optimizewhereyoudon'tneedto.

It'sgoodgeneraladvicetoworkoutwhereyourcodeisspendingmostofitstime,andfocusyouroptimizationthere.It'sobviouslymuchbettertooptimizecodeexecutedmillionsoftimesinsidealoopthancodethatonlyrunsoccasionally.

Page 215: ASP.NET Core 1.0 High Performance

DynamictypingC#isastaticallytypedlanguageandvariabletypesarecheckedatcompiletime,butitdoeshavesomedynamicfeatures.YoucanusethedynamictypeandobjectssuchasExpandoObjecttogetsomeofthefeaturesofadynamicallytypedlanguage.Thevartypeisnotinfactdynamic,andissimplyinferredatcompiletime.

Dynamictypinghasaperformanceandsafetypenalty,soitisbestavoidedifyoucanfindanotherwaytosolveyourproblem.Forexample,theViewBaginASP.NETMVCisdynamic,soitisbestnottouseViewBag,anduseawell-definedviewmodelinstead.Thishasmanyotherbenefitsapartfromperformance,suchassafetyandconvenience.

Page 216: ASP.NET Core 1.0 High Performance

SynchronousoperationsSynchronousmethodsblockexecution,andshouldbeavoidedifpossible,especiallyiftheyaresloworaccessI/O.We'vecoveredasynchronous(asyncforshort)operationsinpreviouschapters.Understandinghowtouseasyncisimportantformodernhighperformanceprogramming,andnewlanguagefeaturesmakeitmoreaccessiblethanever.Ifanasyncmethodisavailable,thenitshouldgenerallybeusedinpreferencetothesynchronousblockingversion.

Theasyncandawaitkeywordsmakeasynchronousprogrammingmucheasierthanitusedtobe,but,ascoveredinChapter3,FixingCommonPerformanceProblems,theeffectsonwebapplicationsarenotalwaysvisibleforaloneuser.Theseconvenientfeaturesallowyoutoservemoreuserssimultaneouslybyreturningthreadstothepoolduringdowntime,whilewaitingforoperationstocomplete.Thethreadscanthenbeusedtoserviceotherusers'requests,whichallowsyoutohandlemoreuserswithlessserversthanotherwise.

Asyncmethodscanbeuseful,butthebiggainscomenotfromwritingasynchronouscode,butfromhavinganasynchronousarchitecture.Wewillcoverdistributedarchitectureinthenextchapter,whenwediscussmessagequeuing.

Page 217: ASP.NET Core 1.0 High Performance

ExceptionsExceptionsshould,asthenamesuggests,bereservedforexceptionalcircumstances.Exceptionsareslowandexpensiveandshouldn'tbeusedasflowcontrolinbusinesslogicifyouknowthataneventislikelytooccur.

Thisisn'ttosaythatyoushouldn'tuseexceptionhandling–youshould.However,itshouldbereservedforeventsthataregenuinelyunexpectedandrare.Ifyoucanpredictaheadoftimethataconditionmayoccurthenyoushouldhandleitexplicitly.

Forexample,thediskbecomingfullandyourcodenotbeingabletowriteafilebecausethereisnospaceisanexceptionalsituation.Youwouldnotexpectthistonormallyhappen,andyoucanjusttrythefileoperationandcatchanyexceptions.However,ifyouaretryingtoparseadatestringoraccessadictionary,thenyoushouldprobablyusethespecialTryParse()andTryGetValue()methodsandcheckfornullvaluesratherthanjustrelyingonexceptionhandling.

Page 218: ASP.NET Core 1.0 High Performance

SummaryInthischapter,wediscussedsometechniquesthatcanimprovetheperformanceofcodeexecutionanddugintotheprojectsthatmakeup.NETCoreandASP.NETCore.Weexploreddatastructures,serialization,hashing,andparallelprogrammingandhowtobenchmarkformeasuringrelativeperformance.

Linearperformancecharacteristicsareeasiertoscaleandcodethatdoesnotexhibitthisbehaviorcanbeslowwhentheloadincreases.Codethathasanexponentialperformancecharacteristicorhaserraticoutliers(whicharerarebutveryslowwhentheyoccur)cancauseperformanceheadaches.Itisoftenbettertoaimforcode,thatwhilebeingslightlyslowerinnormalcasesismorepredictableandperformsconsistentlyoveralargerangeofloads.

Themainlessonhereistonotblindlyapplyparallelprogrammingandotherpotentiallyperformance-enhancingtechniques.Alwaystesttomakesurethattheymakeapositiveimpact,astheycaneasilymakethingsworse.Weaimforthesituationwhereeverythingisawesome,but,ifwe'renotcareful,wecanmakeeverythingawfulbymistake.

Inthenextchapter,you'lllearnaboutcachingandmessagequeuing–twoadvancedtechniquesthatcansignificantlyimprovetheperformanceofasystem.

Page 219: ASP.NET Core 1.0 High Performance

Chapter7.LearningCachingandMessageQueuingCachingisincrediblyusefulandcanbeappliedtoalmostalllayersofanapplicationstack.However,it'shardtoalwaysgetcachingworkingcorrectly,so,inthischapter,wewillcovercachingattheweb,application,anddatabaselevels.Wewillshowyouhowtouseareverseproxyservertostoretheresultsofyourrenderedwebpagesandotherassets.We'llalsocovercachingatlowerlevels,usinganin-memorydatastoretospeedupaccess.Youwilllearnhowtoensurethatyoucanalwaysflush(orbust)yourcacheifyouneedtoforcethepropagationofupdates.

Thischapteralsocoversasynchronousarchitecturedesignusingmessagequeuingandabstractionsthatencapsulatevariousmessagingpatterns.Youwilllearnhowtoperformalongrunningoperation(suchasvideoencoding)inthebackground,whilekeepingtheuserinformedofitsprogress.

Youwilllearnhowtoapplycachingandmessagequeuingsoftwaredesignpatternstoslowoperationssothattheydon'thavetobeperformedinrealtime.You'llalsolearnaboutthecomplexitythatthesepatternscanadd,andunderstandthetradeoffsinvolved.We'llseehowtocombatthesecomplexitiesandmitigatethedownsides,inChapter8,TheDownsidesofPerformance-EnhancingTools.

Thetopicscoveredinthischapterincludethefollowing:

WebcachingbackgroundJavaScriptserviceworkersVarnishproxyandIISwebserversRedisandMemcachedin-memoryapplicationcachingMessageQueuingandmessagingpatternsRabbitMQanditsvariousclientlibraries

Page 220: ASP.NET Core 1.0 High Performance

WhycachingishardCachingishard,butit'snothardbecauseit'sdifficulttocachesomething.Cachingindefinitelyiseasy,thehardpartisinvalidatingthecachewhenyouwanttomakeanupdate.There'sawell-usedquotefromthelatePhilKarltonofNetscapethatgoes:

"ThereareonlytwohardthingsinComputerScience:cacheinvalidationandnamingthings."

Therearealsomanyhumorousvariantsonit,asusedpreviouslythroughoutthisbook.Thissentimentmaybeaslightexaggeration,butithighlightshowcomplexremovingyour"done-computer-stuffTM"fromyour"quick-things-box2.0TM"isperceivedtobe.Namingthingsisgenuinelyveryhardthough.

Cachingistheprocessofstoringatemporarysnapshotofsomedata.Thistemporarycachecanthenbeusedinsteadofregeneratingtheoriginaldata(orretrievingitfromthecanonicalsource)everytimeitisrequired.Doingthishasobviousperformancebenefits,butitmakesyoursystemmorecomplicatedandhardertoconceptualize.Whenyouhavemanycachesinteracting,theresultscanappearalmostrandomunlessyouaredisciplinedinyourapproach.

Whenyouarereasoningaboutcaching(andmessagequeuing),itishelpfultodispeltheideathatdataonlyexistsinasingleconsistentstate.Itiseasierifyouembracetheconceptthatdatahasafreshness,andisalwaysstalebysomeamount.Thisisinfactalwaysthecase,buttheshorttimeframesinvolvedinasmallsystemmeanthatyoucantypicallyignoreitinordertosimplifyyourthinking.However,whenitcomestocaching,thetimescalesarelongerandso,freshnessismoreimportant.Asystematscalecanonlybeeventuallyconsistent,andvariouspartsofitwillhaveadifferenttemporalviewofthedata.Youneedtoacceptthatdatacanbeinmotion,otherwiseyou'rejustnotthinkingfour-dimensionally!

Asatrivialexample,consideratraditionalstaticwebsite.Avisitorloadsapageintheirbrowser,butthispageisnowinstantlyout-of-date.Thepageontheservercouldhavebeenupdatedjustafterthevisitorretrievedit,buttheywillnotknow,astheoldversionwillremainintheirbrowseruntiltheyrefreshthepage.

Ifweextendthisexampletoadatabase-backedwebapplication,suchasanASP.NETorWordPresswebsite,thenthesameprincipleapplies.Auserretrievesawebpagegeneratedfromdatainthedatabase,butitcouldbeout-of-dateassoonasitisloaded.Theunderlyingdatacouldhavechanged,butthepagecontainingtheolddataremainsinthebrowser.

Bydefault,webappstypicallyregenerateHTMLfromtheDBforeverypageload,butthisisincrediblyinefficientifthedatahasnotchanged.Itisonlydonelikethissothatwhenachangeismade,itshowsupimmediatelyassoonasthepageisrefreshed.

However,ausermayhaveanoldpageintheirbrowser,andyouhavelimitedcontroloverthis.

Page 221: ASP.NET Core 1.0 High Performance

Soyoumayaswellcachethispageontheserveraswellandonlyremoveitwhentheunderlyingdatainthedatabasechanges.CachingtherenderedHTMLlikethisisoftenessentialformaintainingperformanceatascalebeyondsimplyasmallnumberofusers.

Page 222: ASP.NET Core 1.0 High Performance

WebcachingThefirstcategoryofcachingthatwe'lldiscussisattheweblevel.Thisinvolvesstoringthefinaloutputofyourwebstackasitwouldbesenttouserssothat,whenrequestedagain,it'sreadytogoanddoesn'tneedtoberegenerated.CachingatthisstageremovestheneedforexpensivedatabaselookupsandCPU-intensiverenderingattheapplicationlayer.Thisreduceslatencyanddecreasestheworkloadonyourservers,allowingyoutohandlemoreusersandserveeachuserrapidly.

Webcachingtypicallyoccursonyourwebserversoronreverseproxyservers,whichyouhaveputinfrontofyourwebserverstoshieldthemfromexcessiveload.Youmightalsochoosetohandthistaskovertoathirdparty,suchasaCDN.Herewewillcovertwopiecesofwebserverandproxyserversoftware,IISandVarnish.However,manymorewebcachingandloadbalancingtechnologiesareavailable,forexample,NGINXorHAProxy.

CachingattheweblayerworksbestforstaticassetsandresourcessuchasJavaScript,CSS,andimages.YetitcanalsoworkforanonymousHTMLthatisrarelyupdatedbutregularlyaccessed,suchasahomepageorlandingpage,whichisunauthenticatedandnotcustomizedforauser.

WetoucheduponproxyserversinChapter3,FixingCommonPerformanceProblems,andcoveredweblayercachingalittleinChapter4,AddressingNetworkPerformance.However,inthischapter,we'llgointomoredetailonwebcaching.

Cachingbackground

Beforewedelveintotheimplementationdetails,ithelpstounderstandalittleabouthowcachingworksontheweb.Ifyoutakethetimetostudythemechanismsatwork,thencachingwillbelessconfusingandlessfrustratingthanifyoujustdivedstraightin.

ItishelpfultoreadandunderstandtherelevantHTTPspecifications.However,don'tassumethatsoftwarealwaysstrictlyadherestothesewebstandardsevenifitclaimsto.

First,let'slookatatypicalnetworksetupwhichyoumaybetraversingwithyourHTTPtraffic.Thefollowingdiagramillustratesanexampleofacommonconfigurationforawebapplication:

Page 223: ASP.NET Core 1.0 High Performance

Asseenintheprecedingdiagram,thelaptopandtabletusersareconnectingthroughacachingforwardproxyserver(whichmaybeonacorporatenetworkoratanISP).Themobileuserisconnectingdirectlyovertheinternet.However,allusersaregoingthroughaCDNbeforereachingyourinfrastructure.

Afteryourfirewall(notshown),thereisanappliancewhichterminatestheTLSconnections,balancestheloadbetweenwebservers,andactsasacachingreverseproxy.Thesefunctionsareoftenperformedbyseparatedevices,butwe'vekeptthingssimplehere.

Copiesofyourresourceswillbekeptonyourwebservers,yourreverseproxy,yourCDN,anyforwardproxies,andinthebrowsersonalluserdevices.Thesimplestwaytocontrolthecachingbehavioroftheseresourcesistousein-bandsignalingandaddHTTPheaderstoyourcontent,declaringcachecontrolmetadataonlyinasingleplace.

It'sgoodpracticetoapplythesamestandardHTTPcachingtechniquestoyourownwebserversandproxieseventhoughyoucouldcustomizethemandflushtheircachesatwill.Thisnotonlycutsdownontheamountofconfigurationthatyouhavetodo,andavoidsduplicatedwork,butitalsoensuresthatanycachesthatyoudon'tcontrolshouldbehavecorrectlytoo.EvenwhenusingHTTPS,thebrowserwillstillperformcachingandtheremayalsobetransparentcorporateproxiesormeddlingISPcaptiveportalsintheway.

HTTPheaders

Page 224: ASP.NET Core 1.0 High Performance

HTTPcachinginvolvessettingcachecontrolheadersinyourresponses.Therearemanyoftheseheaders,whichhavebeenaddedovertheyearsfromdifferentstandardsandvariousversionsoftheprotocol.Youshouldknowhowtheseareused,butyoushouldalsounderstandhowtheuniquenessofacacheableresourceisdetermined–forexample,byvaryingtheURLorbyalteringonlyapartofit,suchasquerystringparameters.

ManyoftheseheaderscanbecategorizedbyfunctionandtheversionofHTTPthattheywereintroducedwith.Someheadershavemultiplefunctionsandsomearenon-standard,yetarealmostuniversallyused.Wewon'tcoveralloftheseheaders,butwewillpickoutsomeofthemostimportantones.

Therearebroadlytwotypesofcachingheadercategories.Thefirstdefinesanabsolutetimeduringwhichthecachecanbereused,withoutcheckingwiththeserver.Theseconddefinesruleswhichtheclientcanusetotestwiththeserverifthecacheisstillvalid.

Mostinstructionalheaders(thosethatissuecachingcommands)fitintooneofthesetwoheadercategories.Inadditiontothese,therearemanypurelyinformationalheaders,whichprovidedetailsabouttheoriginalconnectionandclient,whichmayotherwisebeobscuredbyacache(forexample,theoriginalclientIPaddress).

Someheaders,suchasCache-Control,arepartofthelateststandard,butothers,suchasExpires,aretypicallyusedonlyforbackwardscompatibility,incasethereisanancientbrowseroranoldproxyserverintheway.However,thispracticeisbecomingincreasinglyunnecessaryasinfrastructureandsoftwareisupgraded.

Note

ThelatestcachingstandardinthiscaseisHTTP/1.1asHTTP/2usesthesamecachingdirectives(RFC7234).SomeheadersdatefromHTTP/1.0,whichisconsideredalegacyprotocol.VeryoldsoftwaremayonlysupportHTTP/1.0.

Standardsmaynotbeimplementedcorrectlyinallapplications.Itisasensibleideatotestthatanyobservedbehaviorisasexpected.

TheAgeheaderisusedtoindicatehowlong(inseconds)aresourcehasbeeninacache.Ontheotherhand,theETagheaderisusedtospecifyanidentifierforanindividualobjectoraparticularuniqueversionofthatobject.

TheCache-Controlheadertellscachesiftheresourcemaybecached.Itcanhavemanyvaluesincludingamax-age(inseconds)orno-cacheandno-storedirectives.Theconfusing,yetsubtle,differencebetweenno-cacheandno-storeisthatno-cacheindicatesthattheclientshouldcheckwiththeserverbeforeusingtheresource,whereasno-storeindicatesthattheresourceshouldn'tbecachedatall.Topreventcaching,youshouldgenerallyuseno-store.

TheASP.NETCoreResponseCacheactionattributesetstheCache-ControlheaderandiscoveredinChapter4,AddressingNetworkPerformance.However,thisheadermaybeignored

Page 225: ASP.NET Core 1.0 High Performance

bysomeoldercaches.PragmaandExpiresareolderheadersusedforbackwardcompatibilityandtheyperformsomeofthesamefunctionsthattheCache-Controlheadernowhandles.

TheX-Forwarded-*headersareusedtoprovidemoreinformationabouttheoriginalconnectiontotheproxyorloadbalancer.Thesearenon-standard,butwidely-used,andarestandardizedasthecombinedForwardedheader(RFC7239).TheViaheaderalsoprovidessomeproxyinformation,andFront-End-Httpsisanon-standardMicrosoftheader,whichissimilartoX-Forwarded-Proto.TheseprotocolheadersareusefulfortellingyouiftheoriginalconnectionusedHTTPSwhenthisisstrippedattheloadbalancer.

Tip

IfyouareterminatingtheTLSconnectionsataloadbalancerorproxyserver,andarealsoredirectinguserstoHTTPSattheapplicationlevel,thenitisimportanttochecktheForwardedheaders.YoucangetstuckinaninfiniteredirectionloopifyourwebserversdesireHTTPSbutonlyreceiveHTTPfromtheloadbalancer.Ideally,youshouldcheckallvarietiesoftheheaders,but,ifyoucontroltheproxy,youcandecidewhatheaderstouse.

TherearelotsofdifferentHTTPheadersthatareinvolvedincaching.Thefollowinglistincludessomeoftheonesthatwehaven'tcoveredhere.Thelargequantityofheadersshouldgiveyouanideaofjusthowcomplicatedcachingcanbe.

If-Match

If-Modified-Since

If-None-Match

If-Range

If-Unmodified-Since

Last-Modified

Max-Forwards

Proxy-Authorization

Vary

Cachebusting

Cachebusting(alsoknownascachebursting,cacheflushing,orcacheinvalidation)isthehardpartofcaching.Itiseasytoputaniteminacache,but,ifyoudon'thaveastrategyaheadoftimetomanagetheinevitablechange,thenyoumaycomeunstuck.

Gettingcachebustingcorrectisusuallymoreimportantwithweb-levelcaching.Thisisbecause,withserversidecaching(whichwe'lldiscusslaterinthischapter),youareinfullcontrolandcanresetifyougetitwrong.Amistakeonthewebcanpersistandbedifficulttoremedy.

Inadditiontosettingthecorrectheaders,itishelpfultovarytheURLofresourceswhentheircontentchanges.Thiscanbedonebyaddingatimestamp,butoftenaconvenientsolutionistouseahashoftheresourcecontentandappendthisasaparameter.Manyframeworks,includingASP.NETCore,usethisapproach.Forexample,considerthefollowingJavaScripttaginawebpage:

Page 226: ASP.NET Core 1.0 High Performance

<scriptsrc="js/site.js"></script>

Ifyoumakeachangetosite.js,thenthebrowser(orproxy)won'tknowthatithasalteredandmayuseapreviousversion.However,itwillre-requestitiftheoutputischangedtosomethinglikethefollowing:

<scriptsrc="js/site.js?v=EWaMeWsJBYWmL2g_KkgXZQ5nPe-a3Ichp0LEgzXczKo">

</script>

Herethev(version)parameteristheBase64URLencoded,SHA-256hashedcontentofthesite.jsfile.Makingasmallchangetothefilewillradicallyalterthehashduetotheavalancheeffect.

Note

Base64URLencodingisavariantonstandardBase64encoding.Itusesdifferentnon-alphanumericcharacters(+becomes-while/changesto_)andpercentencodesthe=character(whichisalsomadeoptional).Usingthissafealphabet(fromRFC4648)makestheoutputsuitableforuseinURLsandfilenames.

InASP.NETCore,youcaneasilyusethisfeaturebyaddingtheasp-append-versionattributewithavalueoftrueinyourRazorviewslikeso:

<scriptsrc="~/js/site.js"asp-append-version="true"></script>

Serviceworkers

Ifyouarewritingaclient-sidewebapp,ratherthanasimpledynamicwebsite,thenyoumaywishtoexertmorecontrolovercachingusingnewbrowserfeatures.YoucandothisbywritingyourcachecontrolinstructionsinJavaScript(technicallyECMAScript6(ES6)).Thisgivesyoumanymoreoptionswhenitcomestoavisitorusingyourwebappoffline.

AserviceworkergivesyougreatercontrolthanthepreviousAppCacheAPI.Italsoopensthedoortofeaturessuchasmobilewebappinstallbanners(whichpromptausertoaddyourwebapptotheirhomescreen).However,itisstillarelativelynewtechnology.

Tip

Serviceworkersareanewexperimentaltechnology,andassuch,arecurrentlyonlysupportedinsomerecentbrowsers(partiallyinChrome,Firefox,andOpera).YoumayprefertousethepreviousdeprecatedAppCachemethod(whichisalmostuniversallysupported)untiladoptionismorewidespread.

Informationoncurrentbrowsersupportisavailableatcaniuse.com/#feat=serviceworkersandcaniuse.com/#feat=offline-apps(forAppCache).Amoredetailedserviceworkerbreakdownisavailableatjakearchibald.github.io/isserviceworkerready.

Aserviceworkercandomanyusefulthings(suchasbackgroundsynchronizationandpush

Page 227: ASP.NET Core 1.0 High Performance

notifications),buttheinterestingparts,fromourpointofview,arethescriptablecaches,whichenableofflineuse.Iteffectivelyactsasanin-browserproxyserverandcanbeusedtoimprovetheperformanceofawebapplicationinadditiontoallowinginteractionwithoutaninternetconnection(afterinitialinstallation,ofcourse).

Note

Thereareothertypesofwebworkersapartfromserviceworkers(forexample,audioworkers,dedicatedworkers,andsharedworkers),butwewon'tgointothesehere.Allwebworkersallowyoutooffloadworktoabackgroundtasksothatyoudon'tmakethebrowserunresponsive(byblockingthemainUIthreadwithyourwork).

ServiceworkersareasynchronousandrelyheavilyonJavaScriptpromises,whichwe'llassumeyouarefamiliarwith.Ifyou'renot,thenyoushouldreaduponthem,asthey'reusefulinmanyothercontextsinvolvingasynchronousandparallelscripting.

ServiceworkersrequiretheuseofHTTPS(yetanothergoodreasontouseTLSonyourentiresite).However,thereisanexceptionforlocalhost,soyoucanstilldeveloplocally.

Serviceworkerexample

Toinstallaserviceworker,firstcreateafileforit(whichisservedoverHTTPS).Inthefollowingexample,thisfileiscalledservice-worker.js.Theninsidea<script>tagonyourHTMLpage(alsoservedoverHTTPS),addthefollowingJavaScriptcode:

if('serviceWorker'innavigator){

navigator.serviceWorker.register('service-worker.js',{

scope:'/'

});

}

Theprecedingcodesnippetfirstcheckstoseeifserviceworkersaresupported,andiftheyare,registersyourworker.Youcannowfetchresourcesandaddthemtothecache.Aninterestingperformanceenhancingusecaseforthisisprefetchingresources(thattheusermayneed)aheadoftimeandputtingtheminthecache.Scopeisanoptionalparameterandisn'tstrictlynecessaryinthiscase,asthefileisintherootofthedomain.We'veshownitonlytodemonstrateusage,butitmaybeusefultospecifythisifthefilewasinasubfolder.

Beforegoinganyfurther,youshouldcheckthatyourworkerhasbeeninstalledcorrectly.InChrome,youcanopenthespecialURLchrome://inspect/#service-workerstoseeanyactiveserviceworkers.Forexample,afteropeninginstabail.ukinonetab,youcanopentheserviceworkerinspectorinanother;youshouldseesomethinglikethefollowingscreenshot:

Page 228: ASP.NET Core 1.0 High Performance

Youcanalsovisitchrome://serviceworker-internalsinChrometoseethestatusofallserviceworkersthathavebeenregistered,evenifthesitesaren'tstillopen.Forexample,evenafterclosinginstabail.ukyoushouldcontinuetoseesomethinglikethefollowingscreenshot:

Page 229: ASP.NET Core 1.0 High Performance

YoucanremoveserviceworkersbyclickingtheUnregisterbutton.Iftheserviceisrunning,youwillhaveStopandInspectbuttonsinplaceofStart.ThispagemayberemovedormergedintotheinspectorinafutureversionofChrome.

Tip

IfyouareusinganolderversionofChrome(earlierthan50),youmayseeanerror(net::ERR_FILE_EXISTS)againstyourserviceworkerfileintheconsole;butthisisfine,sodon'tworry.It'ssimplyabuginChromeasittriestoupdateyourserviceworker,butfindsthattherearen'tanychanges.

NowyoucanstartaddingcontenttoyourserviceworkerJavaScriptfile.Wefirstneedtoinstalltheworkerandcachesomefiles,whichisdonewithaneventlistener,asshowninthefollowingcode:

self.addEventListener('install',function(event){

event.waitUntil(

caches.open('cache-v01').then(function(cache){

returncache.addAll([

'/',

'/Content/bootstrap.min.css'

]);

})

);

});

Wehavenamedourcachecache-v01,andprovidedanarrayofresourcestocache.Youwouldprobablyhavemoreentrieshereanddefinethearrayoutsideofthefunction,butwehavekeptthingssimplehereforclarity.

Tip

Don'tcacheyourhomepageifitdynamicallyrenderslivecontent.Youmayalsowanttousecachebustingparametersforresources,asmentionedpreviously.

Wecanthenaddafetcheventlistenertoperformthemagicofcachingandfetchingresources.

self.addEventListener('fetch',function(event){

event.respondWith(

caches.match(event.request)

.then(function(response){

if(response)returnresponse;

varmyReq=event.request.clone();

returnfetch(myReq).then(

function(response){

varmyResp=response.clone();

caches.open('cache-v01')

.then(function(cache){

cache.put(event.request,myResp);

Page 230: ASP.NET Core 1.0 High Performance

});

returnresponse;

}

);

}

)

);

});

Firstwecheckiftherequestedresourceisinthecacheandifitis,wereturnthis.Withpromises,youcanchainthethenfunctionstogetherandfallthroughthem.Ifthereisacachemissduetotheresourcenotbeinginthecache,weperformafetchtoourservertogettheresourceandreturnthis.Wethenaddtheresourcetotheothersbyputtingitinthesamecache.Weclonetherequestandresponse,becausetheyarestreamsandcanonlybeconsumedonce.

Note

ThefetchfunctionisthemodernversionofanXMLHttpRequest(XHR)andisusedtoretrievedataoverthenetwork.Youcan'tuseasynchronousXHRinsideofaserviceworker,asthey'redesignedtobeasynchronous.

Youcaninspectyourserviceworkerandthecachesinmoredetailbyusingthebrowserdevelopertools(F12).OntheResourcestab,selectServiceWorkersandyouwillseesomethinglikethefollowingscreenshot:

Page 231: ASP.NET Core 1.0 High Performance

IfyouselectCacheStorage,youwillseethecontentsofthecache,whichwilllooksomethinglikethefollowing:

Youcanrefreshthecacheanddeleteitemsbyrightclicking.TheApplicationCache,aboveCacheStorage,wouldshowthedeprecatedAppCacheresources.Asyounavigatearound,yoursitepageswillbeaddedtothecache(thesepagesshouldbesuitableforcaching,astheywon'tberequestedfromtheserverafterthisifusingourdemocode).Afterthis,onceyourefreshthecacheview,youshouldseemoreentrieslisted,whichmaylooksomethinglikethefollowingscreenshot:

Page 232: ASP.NET Core 1.0 High Performance

Youcanseethatthecacheentriesarelistedalphabeticallyandnotintheorderinwhichtheywereaddedtothecache.Thesepageswillnowbeasnapshot,fixedatthepointintimethattheywereretrieved.Thismaynotbethefunctionalitythatyouwant!

Forsimplicity,theserviceworkerthatwe'vebuilthereisatrivialexampleandyouwouldlikelywanttoexpandittoatleasthandlethecasewherethenetworkfetchfailsbyaddingacatchstatement.Forexample,youcouldserveapreviouslycachedofflinefallbackpageinitsplace.Youshouldalsocheckthatyou'renotcachingerrorpagesfromtheserver,sotesttheresponsestatuscode.

Youalsoneedtocarefullyconsideryourcacheinvalidationstrategy.Serviceworkersgiveyouthetoolstobuildthis,astheydon'tmakeasmanyassumptionsastheHTML5AppCachedid.Forexample,youcannowprogrammaticallydeleteentriesfromthecache.

We'llleaveithereforclient-sidescriptcontrolledcaching,butyoumaywanttolookintothisinmoredetail,especiallyoncethespecificationhasstabilizedandbrowsersupportismorewidespread.TherearemanyothernewfeaturesnowavailableinJavaScript,whichmakeasyncprograminglikethiseasierthanitusedtobe.Forexample,arrowfunctions,whicharesimilartoLINQlambdaexpressionsinC#.

Webandproxyservers

Cachingfromaserver'spointofviewisintimatelylinkedtoclient-sidecachinginthebrowser.In

Page 233: ASP.NET Core 1.0 High Performance

additiontostoringresourcesontheserver,theheadersthatyousetwillbeusedtocontrolcacheseverywhere.

TheHTTPheadersthatyousetareusedbybothproxyserversandbrowsers,includingnotonlystandardbrowsing,butalsofetchingfromaserviceworker.Forexample,iftheCache-Controlheaderspecifiesno-store,thenyouwon'tbeabletoaddtheresourcetoacachefromyourworker.

IIS

InternetInformationServices(IIS)isMicrosoft'swebserver.ItcanbeusedtoservecontentfromyourASP.NETapplicationorasaproxyserveralongwithmanyotherthingssuchasFTP.AlthoughIISdoessupportoutputcaching,theOutputCacheactionattributeisnotavailableinASP.NETCore.Yet,youcanuseResponseCachetosetthecorrectheadersinstead,ascoveredinChapter4,AddressingNetworkPerformance.

IIScanalsobeusedasaproxy,forexample,infrontoftheKestrelwebserveronasinglemachine.However,whencachingformultiplewebservers,youmaybebetteroffusingdedicatedproxyserversoftwaresuchasVarnish.

Varnish

VarnishisafreereverseproxyserverthatrunsonUnix-likeoperatingsystemssuchasLinuxandFreeBSD.Youcaninstallitwithyourpackagemanager(forexample,aptoryum)orprovisionaproxyserverwithDevOpssoftwaresuchasCheforPuppet.ToconfigureVarnish,youuseadomain-specificlanguage(DSL)calledVarnishConfigurationLanguage(VCL).

Note

YoucanreadmoreaboutVarnishatvarnish-cache.org.

Youshouldn'tneedtoconfigureVarnishtoomuchifyouareusingHTTPcachingheaderscorrectly.YoucanalsousethecustomHTTPPURGEmethodtoremoveentriesfromthecache,whichworkswiththeSquidproxysoftwaretoo.YoumayoccasionallyseeacrypticgurumeditationerrorifVarnishisnotproperlyconfigured,butyoushouldbeabletotrackdowntheissueintheVarnishlogs.Itcouldindicatethatnohealthywebserversareavailable.

Varnishconfigurationisbeyondthescopeofthisbook,butit'sverywelldocumentedontheVarnishwebsite.Ifyoudon'twanttorunyourownproxyserver,thenyoucoulduseaCDN.YoumaystillwantyourownproxyinadditiontousingaCDN,aslargeCDNs,withmanypointsofpresence(PoP),mightrequestthesameresourceviaeachPoP,andnotshareassetsacrossthem.Thiscanbeanissueifyoupayalotforbandwidth,althoughsomeCDNshaveafeature(oftencalledoriginshielding)thatcanhelpwiththis.

Workingwithacontentdeliverynetwork

Acontentdeliverynetworkiscommonlyusedintwoways–asaproxyforoffloadingyourcontent

Page 234: ASP.NET Core 1.0 High Performance

orasahostingproviderforcommonthirdpartylibrariesandframeworks.YoucanuseadynamicCDNservice,suchasCloudFlareorAkamai,forthefirstusecase,butthesecondsituation(usingastaticCDNfromGoogleorMicrosoft)ismorecommonandthat'swhatwe'llcoverhere.

AlthoughusingaCDNforyourlibraries,suchasjQueryandTwitterbootstrap,isbecominglessusefulwiththeadoptionofHTTP/2,itcanstillbehelpfulforreducingyourhostingcosts.IfyouuseapopularCDNandlibrary,thentheusermayalsoalreadyhaveacopy.Forexample,iftheuserhasbeentoanothersitethatusesjQueryfromGoogle'sCDN,thenitwillalreadybeintheirbrowsercache.

ItisessentialtohaveafallbackcopyofwhateverfilesyourequirefromaCDN.ThisiseasierthaneverwiththeRazorviewenginesupportbuiltintoASP.NETCore.

ThefollowingcodeshowshowjQueryisincludedinthedefaultMVCRazorlayout,fornon-developmentenvironments.BoththeCDNandlocalversionsarespecifiedalongwithatest.

<script

src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.1.4.min.js"

asp-fallback-src="~/lib/jquery/dist/jquery.min.js"

asp-fallback-test="window.jQuery">

</script>

Theprecedingcodesnippetnotonlyrendersthestandard<script>tagfortheMicrosoftCDN,butalsoaddsthefollowinginlineJavaScriptafterwards,whichincludesthelocalversioniftheCDNloadfails:

(window.jQuery||document.write(

"<scriptsrc="\/lib\/jquery\/dist\/jquery.min.js"><\/script>"));

Previously,youwouldhavetodothismanually,usuallyinahurrywhenyourCDNwentdown.ThisnewhelperalsoworksforotherscriptsandCSSfiles.Formoreexamples,takealookat_Layout.cshtmlinthedefaulttemplate.

Tip

It'simportanttouseasecureHTTPSconnectiontoCDNresourcesinordertoavoidmixedcontentwarningsorscriptloadingerrorsinbrowsers;mostpopularCDNsnowsupportHTTPS.ForadditionalinformationonCDNs,seeChapter4,AddressingNetworkPerformance.

Whennottocache

Therearecertainsituationswhenyoushouldn'tcachepagesoratleastyouneedtobeverycarefulinhowyougoaboutit.Asageneralruleofthumb,cachingtherenderedoutputofanauthorizedpageisabadidea.Inotherwords,ifauserhasloggedintoyoursite,andyouareservingthemcustomizedcontent(whichcouldeasilybesensitive),thenyouneedtoconsidercachingverycarefully.

Ifyouaccidentallyserveoneuser'scachedcontenttoanother,thenatbest,itwillbeannoying,as

Page 235: ASP.NET Core 1.0 High Performance

thepersonalizationwillbeincorrect.Atworst,youcouldexposeprivateinformationtothewrongpersonandpotentiallygetintolegaltrouble.

Note

ThisissimilartothegeneralruleofnotuniversallyenablingCORSifyouserveauthenticatedcontent.Itcanbedonesuccessfully,butyouneedtounderstandthemechanismsinordertoconfigureittoworksafely.

Forcaching,youwouldneedauniqueidentifierintheURLthatcan'tbeguessed.Somedynamiccachecontrolsystems,usedbynetworkappliancesandCDNs,canmakeuseofcookiesforthis,butit'sbeyondnormalHTTP-basedcachecontrol.Itissimilartohowyoumightneedstickysessionsonaloadbalancer,becauseyourapplicationwasnotdesignedtobestateless.

Forauthenticatedcaching,itmaybebettertonotcacheattheweblevelandinsteadcacheattheapplicationlevelandbelow.Thisallowsyoutocachesmallerdiscretechunksratherthanawholepage,whichcanenhancereusability.

Page 236: ASP.NET Core 1.0 High Performance

ApplicationlayercachingApplicationlevel(orlayer)cachingmeansstoringreusabledatatemporarilyinsideyourinfrastructure,butnotinthemaindatabase.Thiscanbeinthememoryofyourapplicationorwebservers,butwithmultipleservers,thistendstobeinadistributedin-memorystoresuchasMemcachedorRedis.

Youcan,ofcourse,usebothin-memorystoresonyourwebserversandacentralizedcache.However,ifyouhavemultiplewebservers,thenyouwillneedawaytosynchronizethecaches.Youcanusepublish-subscribe(pub/sub)messagingforthis,whichwewillcoverlaterinthischapter.

Thefollowingdiagramshowsasimplecentralizedcachingsetup.Inarealsituation,youwouldprobablyhavemultipleclusteredcacheservers.

Thewebserverscannowaskthecacheifthedatatheyneedisinthere,beforegoingtothedatabase.ThisreducesloadontheDBandisoftenquicker,asthedatawillbeinmemoryifpresent.Ifthereisacachemissandthedatabasedoesneedtobequeried,thentheresultcanbewrittentothecacheforotherserverstouse.

Page 237: ASP.NET Core 1.0 High Performance

Redis

Redisisapopularin-memorystorethatcanalsopersistdatatodiskforpermanentstorage.ItrunsbestonLinux,butaversionisavailableonWindowsfordevelopmentpurposes.Redisadditionallysupportspub/submessaging,whichcanbeusefulforcacheinvalidation.YoucanreadmoreaboutRedisatredis.io.

YoumaywishtousetheWindowsversionofRedisforlocaldevelopmentwork,butstilldeploytothesupportedversiononLinux.YoucangettheWindowsversionatgithub.com/MSOpenTech/redisoryoucouldruntheLinuxversioninavirtualmachine,perhapsusingDockerorVagrant.

RediscacheisprovidedasaserviceonbothAzureandAWS(ElastiCacheoffersbothMemcachedandRedis).Youdon'tneedtomanageyourownserver,butbecausethetechnologyisnotcloud-specific,youwon'tgetlockedinifyouwanttomigrateinthefuture.

AsRediskeepstheentiredatasetinmemory,but,isalsoabletopersisttodisk,itcanbesuitableasaprimarydatastoreunlikeMemcached.However,itismorecommonlyusedonlyasacache,especiallyifacloudserviceisusedandit'spairedwithaclouddatabasesuchasAzureSQLDatabaseorAWSRelationalDatabaseService(RDS).

Therearetworecommended.NETC#clientsforRedisa–ServiceStack.RedisandStackExchange.Redis.TheStackExchangeclientisusedheavilyonsitessuchasStackOverflowandiseasiertousecorrectlythanthetheServiceStackone.Youcanreadmoreaboutitatgithub.com/StackExchange/StackExchange.RedisandinstallitviaNuGet.

Ifusingcachingattheapplicationlayer,thenyouwillprobablyneedtowriteasignificantamountofcustomcode.Youwillalsoneedtoworkoutwhatformattoserializeyourdataintoforstorageinthecache.Ifservingdirectlytobrowsers,thenJSONcouldbeuseful.Butifistobeusedinternally,thenyoumaypreferabinaryformatsuchasMSBondorProtocolBuffers.

Tip

SeeChapter6,UnderstandingCodeExecutionandAsynchronousOperations,formoreonserializationformatsandlibraries.

Databaseresultsetcaching

Cachingatthedatabaselevelissimilartoapplicationlevelcaching,anditusessimilarinfrastructure,butrequireslesscustomcode.YoucanusethecachingfeaturesbuiltintoanO/RM,whichmaymakeiteasiertoretrofit.

Note

Whenwetalkaboutdatabasecachinghere,wearenotreferringtocachingwithinthedatabaseengineitself.DBsuseextensiveperformanceenhancingtechniques,suchasquerycaching,and

Page 238: ASP.NET Core 1.0 High Performance

holdlotsoftheirdatainmemory.However,thisisabstractedawayfromthedeveloper,andthecachingwementionherereferstostoringtheoutputofaqueryinanapplicationcache.Thisissimilarto,butsubtlydifferentfrom,theprevioussection,whereyouwouldbestoringcustomobjects.

InthecontextofO/RMs(suchasNHibernateandEntityFramework),thisisknownassecond-levelcaching.Firstlevelcachinggenerallyalreadyhappenspersession,bydefault,andisusedtohelpavoidthingslikeSelectN+1problems.Second-levelcachingoperatesatalevelhigherthanindividualtransactionsandallowsyoutosharecacheddataacrossmultipledatabasesessionsoveryourentireapplication.

Page 239: ASP.NET Core 1.0 High Performance

MessagequeuingAmessagequeue(MQ)isanasynchronousandreliablewayofmovingdataaroundyoursystem.Itisusefulforoffloadingworkfromyourwebapplicationtoabackgroundservice,butcanalsobeusedtoupdatemultiplepartsofyoursystemconcurrently.Forexample,distributingcacheinvalidationdatatoallofyourwebservers.

MQsaddcomplexityandwewillcovermanagingthisinChapter8,TheDownsidesofPerformance-EnhancingTools.However,theycanalsoassistinimplementingamicroservicesarchitecturewhereyoubreakupyourmonolithintosmallerparts,interfacedagainstcontracts.Thiscanmakethingseasiertoreasonaboutwithinlargeorganizations,wheredifferentteamsmanagethevariouspartsoftheapplication.Wewilldiscussthisinmoredetailinthenextchapter,asqueuesaren'ttheonlywayofimplementingthisstyleofarchitecture.Forexample,HTTPAPIscanalsobeusedtodothis.

Page 240: ASP.NET Core 1.0 High Performance

CoffeeshopanalogyIfusingMQs,thenyoumayneedtoimplementextrareconciliationlogicforerrorsoccurringinthebackground.Thisisbestexplainedwithacoffeeshopanalogy.

Ifyoupurchaseatakeawaycoffee,perhapsinabranchofapopularmultinationalchainoffranchisedcaffeinatedbeverageoutlets(thatdislikespayingtax),thenyourdrinkispreparedasynchronouslytothepaymentprocessing.Typically,youplaceyourorderandabaristawillstarttoprepareyourcoffee,beforeyouhavepaidforit.Additionally,youwillnormallypaybeforereceivingyourdrink.Therearemanythingsthatcouldgowronghere,buttheyarerareenoughfortheextracosttobeworthit,asitspeedsuptheordinaryworkflow.

Forexample,youmayfindthatyouareunabletopayafterplacingyourorder,butthecoffeecreationprocesshasalreadybegun.Thiswouldresultinwastedstock,unlessthereisanothercustomerwaitingwhomitcouldbeusedfor.Orperhaps,afteryouhavepaid,thebaristadiscoversthatakeyingredientforyourorderismissing.Theycouldeitherofferyouarefund,ornegotiateadifferentdrink.

Althoughmorecomplex,thisprocessisclearlysuperiortoperformingtheactionsinseries.Ifyouhadtodemonstratethatyouhadthemeanstopay,yourdrinkwasmade,andthenyoucompletedpaying,onlyonecustomercouldbeservedatatime.Assumingthereareenoughstaff,paymentprocessinganddrinkpreparationcanbeperformedinparallel,whichavoidsalongqueueofcustomers.

Runningacoffeeshopinthiswaymakesintuitivesenseandyet,inawebapplication,itiscommontohavearelativelylongrunningtransactioncompletebeforeinformingtheuseroftheresult.Insomesituations,itmaybebettertoassumetheactionwillsucceed,informtheuserofthisimmediatelyandhaveaprocessinplaceincaseitgoeswrong.

Forexample,paymentprocessinggatewayscanbeslowandunreliable,soitmaybebettertochargeauser'screditcardafteracceptinganorder.However,thismeansthatyoucannolongerhandleafailurebyshowingtheuseranerrormessage.Youwillhavetouseothermethodsofcommunication.

WhenyouorderitemsonAmazon,theytakepaymentdetailsimmediately,buttheyprocessthepaymentinthebackgroundandsendyoue-mailswiththeresults.Ifthepaymentfailed,theywouldneedtocanceltheorderfulfilmentandnotifyyou.Thisrequiresextralogic,butisquickerthanprocessingthepaymenttransactionandcheckingstockbeforeconfirmingtheorder.

Page 241: ASP.NET Core 1.0 High Performance

MessagequeuingstylesThereare,broadly,twostylesofmessagequeuing–withandwithoutacentralbroker.Withabroker,allmessagesgothroughahub,whichmanagesthecommunication.ExamplesofthisstyleincludeRabbitMQ,ActiveMQ,andMSBizTalk.

Therearealsobrokerlessstyles(thatdon'tuseabroker),wherecommunicationbetweennodesisdirect.AnexampleofthisstyleincludesZeroMQ(ØMQ),whichhasanativeC#portcalledNetMQ.

Cloudqueuingservices,includingAzureServiceBus,AzureQueuestorage,andAWSSimpleQueueService(SQS),arealsoavailable.However,aswithallnon-genericcloudservices,youshouldbewaryofgettinglockedin.TherearecloudprovidersofstandardRabbitMQhosting,whichmakesmigrationtoyourowninfrastructureeasierdownthelineifyoudon'tinitiallywanttorunyourownserver.Forexample,CloudAMQPoffersRabbitMQhostingonmultiplecloudplatforms.

RabbitMQimplementstheAdvancedMessageQueuingProtocol(AMQP),whichhelpstoensureinteroperabilitybetweendifferentMQbrokers,forexample,toallowcommunicationwiththeJavaMessageService(JMS).AzureServiceBusalsosupportsAMQP,butabigbenefitofRabbitMQisthatyoucaninstallitonyourdevelopmentmachineforlocaluse,withoutaninternetconnection.

ThereisalsoMicrosoftMessageQueuing(MSMQ),whichisbuiltintoWindows.Whilethisisusefulforcommunicationbetweenprocessesonasinglemachine,itcanbetrickytogetitworkingreliablybetweenmultipleservers.

Page 242: ASP.NET Core 1.0 High Performance

CommonmessagingpatternsTherearetwotypesofcommonmessagingpatterns:point-to-pointunicastandpublish-subscribe.Thesesendmessagestoasinglerecipientandmanyrecipientsrespectively.

Unicast

Unicastisthestandardmessagequeuingapproach.Amessageissentfromoneserviceprocessorsoftwareagenttoanother.Thequeuingframeworkwillensurethatthishappensreliablyandwillprovidecertainguaranteesaboutdelivery.

Thisapproachisdependable,butdoesn'tscalewellasasystemgrows,becauseeachnodewouldneedtoknowaboutallitsrecipients.Itwouldbebettertolooselycouplesystemcomponentstogethersothattheydon'tneedtohaveknowledgeaboutanyoftheothers.

Thisisoftenachievedbyusingabroker,whichhasthreemainadvantages:

Byusingabroker,youcandecoupleprocessesfromeachothersothattheyaren'trequiredtoknowaboutthesystemarchitectureorbealiveatthesametime.Theyonlycareaboutthemessagetypesandthebrokertakescareofroutingthemessagetothecorrectdestination.Brokerqueuesenableaneasydistributionofworkpattern,especiallywhencombiningmultipleproducers.Youcanhavemultipleprocessesconsumingthesamequeueandthebrokerwillallocatemessagestotheminaround-robinfashion.Thisisasimplewayofbuildingaparallelsystem,withouthavingtodoanyasynchronousprogrammingorworryingaboutthreads.Youcanjustrunmultiplecopiesofyourcode,perhapsonseparatemachinesifconstrainedbyhardwareandtheywillrunsimultaneously.Youcaneasilybroadcastormulticastaparticulartypeofmessage,perhapstoindicatethataneventhasoccurred.Otherprocessesthatcareaboutthiseventcanlistentothemessageswithoutthepublisherknowingaboutthem.Thisisknownasthepub/subpattern.

Pub/sub

Pub/sub,asthenamesuggests,iswhereasoftwareagentpublishesamessageontoaqueue,andotheragentscansubscribetothattypeofmessagetoreceiveit.Whenamessageispublished,allsubscribersreceiveit,butcruciallythepublisherdoesnotrequireanyknowledgeofthesubscribersorevenneedtoknowhowmanythereare(orevenifthereareanyatall).

Pub/subisbestdonewiththebrokerstyleofmessagequeuingarchitecture.Itcanbedonewithoutabroker,butitisnotparticularlyreliable.Ifyourusecasecantoleratemessageloss,thenyoumaybeabletogetawaywithoutabroker.But,ifyourequireguaranteeddelivery,thenyoushoulduseone.UsingtheRabbitMQbrokeralsoallowsyoutotakeadvantageofexchangeswhichcanperformcomplexroutingofmessages.

Ifyoudon'twanttolosemessages,thenyouneedtocarefullydesignyourpub/subsystem(evenifusingabroker).Apublishedmessagethathasnosubscribersmaysimplydisappearintotheetherwithoutatraceandthismightnotbewhatyouwant.

Page 243: ASP.NET Core 1.0 High Performance

Thefollowingdiagramshowsthedifferencesbetweensimplemessageforwarding,workdistribution,andpub/sub:

Clearly,ifyourequireareliablebroker,thenitneedstobehighlyavailable.Typically,youwouldclustermultiplebrokerstogethertoprovideredundancy.Usingabrokeralsoallowsyoutowritecustomrulestodefinewhichsubscribersreceivewhatmessages.Forexample,yourpaymentsystemmayonlycareaboutorders,butyourloggingservermaywanttogetallmessagesfromallsystems.

Youwillwanttomonitornotonlyyourbrokerserversbutalsothelengthofthequeues.Inother

Page 244: ASP.NET Core 1.0 High Performance

words,thenumberofmessagesineachqueueshouldalwaysbesteadyandclosetozero.Ifthenumberofmessagesinaqueueissteadilygrowing,thismightindicateaproblemwhichyouroperationsteamwillneedtoresolve.Itmaybethatyourconsumerscan'tprocessmessagesfasterthanyourproducersaresendingthemandyouneedtoaddmoreconsumers.ThiscouldbeautomatedandyourmonitoringsoftwarecouldSpin-upanextrainstancetoscaleyoursystem,meetingatemporaryspikeindemand.

Page 245: ASP.NET Core 1.0 High Performance

RabbitMQRabbitMQisafreeandopensourcemessagequeuingserver.It'swritteninErlang,whichisthesamerobustlanguagethatWhatsAppusesforitsmessagingbackend.

RabbitMQiscurrentlymaintainedbyPivotal(whoselabsalsomakethePivotalTrackeragileprojectmanagementtool),butitwasoriginallymadebyLShift.ItwasthenacquiredbyVMwarebeforebeingspunoutasajointventure.It'sdistributedundertheMozillaPublicLicense(MPL)v1.1,anolderversionofthelicensethattheFirefoxwebbrowseruses.

ThemessagingservercanbeusedfrommanydifferentlanguagesandframeworkssuchasJava,Ruby,and.NET.Thiscanmakeithelpfulforlinkingdiverseapplicationstogether,forexample,aRailsappthatyouwanttointerfacewithanASP.NETCoreapporC#service.

Note

YoucanreadmoreaboutRabbitMQanddownloadbuildsfromrabbitmq.com.

RabbitMQismoremodernthansystemssuchasMSMQandincludesfeaturessuchasanHTTPAPIandawebadminmanagementinterface.AlongwithHTTPandAMQP,italsosupportsSimpleTextOrientatedMessagingProtocol(STOMP)andMQTT,whichisusefulforlightweightInternetofThings(IoT)hardwareapplications.AlloftheseprotocolsimproveinteroperabilitywithothermessagingsystemsandtheycannormallybesecuredusingstandardTLS.

Thewebmanagementinterfaceshowsyouhowmanymessagesareflowingthroughyourqueues,andhowtheyareconfigured.Italsoallowsyoutoadministeryourqueues(taskssuchaspurgingordeletingmessages)andlookssomethinglikethefollowingscreenshot:

Page 246: ASP.NET Core 1.0 High Performance
Page 247: ASP.NET Core 1.0 High Performance

QueuingframeworksandlibrariesYouwilltypicallywanttouseaprebuiltclientlibraryorframeworktointeractwithyourmessagequeues.Thereareofficiallibrariesinmanydifferentlanguagesforthevariousqueuingsystems,whichofferlow-levelaccess.Forexample,RabbitMQhasanofficial.NET/C#clientlibrary.

However,therearealsootheropinionatedclientsandframeworks,whichofferahigherlevelofabstractionforcommonmessagingtasks.Forexample,NServiceBus(NSB),whichsupportsRabbitMQ,MSMQ,SQLServer,andAzure,isacommercialoffering.

AfreealternativetoNSBisMassTransit(masstransit-project.com),whichisalightweightservicebusanddistributedapplicationframework.IthasalsospunoutthesuperconvenientTopshelfframework(topshelf-project.com),whichmakescreatingWindowsservicesreallyeasy.Neitheryetrunson.NETCore,butsupportforbothoftheseprojectsisinprogress.

OneinterestingfeatureofMassTransit(andNSB)issupportforsagas.Asagaisacomplexstatemachinethatallowsyoutomodelthestoryofanentireworkflow.Ratherthandefiningindividualmessagesanddocumentinghowtheyallfittogether,youcanimplicitlycapturethegoldenpathanderrorflowswithinasaga.

ThereisalsotheexcellentopensourcelibraryEasyNetQ,whichmakesimplementingpub/subonRabbitMQtrivial.YoucanreadaboutitatEasyNetQ.com.Unfortunately,neithertheofficialRabbitMQclientnorEasyNetQsupport.NETCoreatthetimeofwriting.However,workisinprogressfortheofficialclientandEasyNetQhastheissuelogged.

TheRabbitMQteamisworkingonanew,asynchronousofficial.NETclient,whichwillonlytarget.NETCoreandtheTaskParallelLibrary(TPL).WecoveredtheTPL,whichispartoftheparallelextensionsthatalsoincludePLINQ,inChapter6,UnderstandingCodeExecutionandAsynchronousOperations.

Hopefully,bythetimeyoureadthis,thingswillhavestabilizedandyouwillbeabletouseRabbitMQwith.NETCore.Otherwise,youcanusethetraditional.NETFramework,whichmaycurrentlybemoresuitablefortheenterprisestyleapplicationsthatnormallyrequiremessagequeuing.

However,youcouldlookintousingRestBus,whichisaRabbitMQlibrarythatsupportsASP.NETCore.Youcanreadmoreaboutitatrestbus.org;italsosupportsbothWebAPIandServiceStack.

Note

Libraryandframeworksupportfor.NETCoreandASP.NETCorecanchangerapidly,socheckANCLAFS.comforthelatestinformation.Feelfreetohelpoutandcontributetothislistortoanyoftheopensourceprojectsthatneedporting.

Page 248: ASP.NET Core 1.0 High Performance

SummaryInthischapter,wehaveinvestigatedthevarioustoolsandmethodsusedforcachingandmessagequeuing.Thesetwotechniquesofferdifferentwaysofimprovingtheperformanceofyoursystembymovingdatatootherlocationsandnothavingonemassivemonolithdoeverything.

Thesearebothadvancedtopicsanddifficulttocoverinsuchasmallspace.Hopefully,youhavebeenintroducedtosomefreshideasthatcanhelpyouwithsolvingproblemsinoriginalways.Ifyouhavediscoveredanewtechnologythatyouthinkwillassist,you'reencouragedtoreadthedocumentationandspecificationsforalloftheimplementationdetails.

However,beforeyoudivein,youshouldunderstandthatadvancedtechniquesarecomplexandhavedownsides,whichcanreduceyourdevelopmentspeed.Inthenextchapter,we'lllearnaboutthesedownsidesanddiscoverapproachesformanagingcomplexitysuchasmicroservices.

Page 249: ASP.NET Core 1.0 High Performance

Chapter8.TheDownsidesofPerformance-EnhancingToolsAlotofthetopicsthatwecoveredinthisbookimproveperformanceatacost.Yourapplicationwillbecomemorecomplicatedandhardertounderstandorreasonabout.Thischapterdiscussesthesetrade-offsandhowtomitigatetheirimpact.

Youshouldimplementmanyoftheapproachesthatyoulearnedsofarinthisbookonlyifyourequirethemandnotjustbecausetheyareinterestingorchallenging.It'softenpreferabletokeepthingssimpleiftheexistingperformanceisgoodenough.

Youwilllearnhowtomakepragmaticchoicesaboutwhattechnologiesandtechniquesyoushoulduse.You'llalsoseehowtomanagethecomplexitiesifyouchoosetouseadvancedmethods.

Topicscoveredinthischapterincludethefollowing:

ManagingcomplexitywithframeworksandarchitectureBuildingahealthyculturetodeliverhighperformanceDistributeddebuggingandperformanceloggingUnderstandingstatisticsandstaledata

Manybooksandguidesonlyfocusonthepositivesofnewtoolsandframeworks.However,nothingcomesforfree,andthereisalwaysapenalty,whichmaynotbeimmediatelyobvious.

Youmaynotfeeltheeffectsofthechoicesthatyoumake,particularlyintechnicalarchitecture,foralongtime.Youmightnotdiscoverthatadecisionwasbaduntilyoutrytobuildonit,perhapsyearslater.

Page 250: ASP.NET Core 1.0 High Performance

ManagingcomplexityOneofthemainproblemswithperformance-enhancingtechniquesisthattheytypicallymakeasystemmorecomplicated.Thiscanmakeasystemhardertomodifyanditmayalsoreduceyourproductivity.Therefore,althoughyoursystemrunsfaster,yourdevelopmentisnowslower.

Wecommonlyfindthiscomplexityprobleminenterprisesoftware,althoughusuallyfordifferentreasons.Typically,manyunnecessarylayersofabstractionareused,supposedlytokeepthesoftwareflexible.Ironically,thisactuallymakesitslowertoaddnewfeatures.Thismayseemcounterintuitive,untilyourealizethatsimplicitymakeschangeeasier.

Note

There'sasatiricalenterpriseeditionofthepopularprogrammerinterviewcodingtestFizzBuzz,whichisavailableatfizzbuzz.enterprises.It'sgoodinspirationforhownottodothings.

Ifyoudon'tneedafeatureyet,thenit'softenbesttoleaveitoutratherthanbuildingitjustincaseyoumightneeditinthefuture.Themorecodeyouwrite,themorebugsitwillhave,andtheharderitwillbetounderstand.Over-engineeringisacommonnegativepsychologicaltraitthatiseasytofallvictimtoifyouaren'tawareofit,andmarketersoftenexploitthis.

Foranon-softwareexample,four-wheeldriveSUVsaresoldtopeoplewhowillneverneedtheiroff-roadcapabilitiesonthefalsepremisethatitmaypotentiallycomeinusefulsomeday.Yetthefinancial,safety,environmental,andparkingconveniencecostsoutweighthissupposedbenefitbecauseit'sneverused.

Weoftentermthisdevelopmentadvicefromtheextremeprogramming(XP)philosophy,YouAren'tGoingtoNeedIt(YAGNI).Althoughwesometimesuseslightlydifferentwords,themeaningisthesame.YAGNIadvocateskeepingthingssimpleandonlybuildingwhatyouimmediatelyneed.

Thisdoesn'tmeanthatyoushouldmakeyoursoftwarehardtomodify.It'sstillimportanttostayflexible,justdon'taddfeaturesbeforeyouneedthem.Forexample,addinganabstractioninterfacewhenthereisonlyasingleimplementationmaybeoverkill.Youcouldeasilyadditalongwiththesecondimplementationifandwhenyoubuildit.

It'sdifficulttomovefastyetnotbreakthingswhendoingso.Howyouachievehighreliabilityinadditiontoaconsistentlygooddevelopmentspeedwilldependonmanythingsthatarespecifictoyoursituation,suchasyourteamsize,organizationalstructure,andcompanyculture.

Onemethodistoembracechangeanddevelopasystemwhereyoucanrefactoryourcodeinconfidence.Usingastatically-compiledlanguage,suchasC#,isagoodstart,butyoushouldalsohaveacomprehensivetestsuitetoavoidregressions.

Youshoulddesignasystemsothatitislooselycoupled,whichmeansthatyoucanchangepartsin

Page 251: ASP.NET Core 1.0 High Performance

isolationwithoutalotofknock-oneffects.Thisalsomakesiteasiertounittestandunittestsareinvaluabletorefactorinconfidenceandpreventfunctionalregressions.

WewillcovertestingandautomationwithaContinuousIntegration(CI)workflowinthenextchapter.Inthischapter,wewilltalkmoreaboutvariousarchitecturalstylesthatcanhelpyoumaintainyourapplication.

Page 252: ASP.NET Core 1.0 High Performance

UnderstandingcomplexityWhenlearningaboutnewwaysofdoingthings,youshouldavoiddoingthemwithoutunderstandingthereasons.Youshouldknowthebenefitsanddownsidesandthenmeasurethechangestoprovethattheyarewhatyouexpect.Don'tjustblindlyimplementsomethingandassumeitimprovesthesituation.Trytoavoidcargocultprogrammingandalwaysobjectivelyevaluateanewapproach.

Note

Cargocultprogrammingisthepracticeofemulatingsomethingsuccessfulbutfailingtounderstandthereasonswhyitworks.ItsnamecomesfromthecargocultsofthePacificwhobuiltfalseairstripsaftertheSecondWorldWartoencouragecargodelivery.Weuseittodescribemanythingswherecorrelationhasbeenconfusedwithcausation.

Oneexampleisacompanyencouraginglonghourstodeliveraprojectbecausetheyhaveheardofsuccessfulprojectswhereemployeesworkedlonghours.However,theyfailtounderstandthatthesuccessfulprojectandlonghoursarebothindependentbyproductsofahighlymotivatedandcompetentworkforce,andtheyarenotdirectlyrelated.

It'simportanttokeepcodereadable,notjustforothersonyourteamornewmembersbutalsoforyourselfinthefuture(whenyouwillforgethowsomethingworksandwhyyouwroteitinthisway).Thisdoesn'tsimplymeanwritinghelpfulexplanatorycommentsinthecode,althoughthisisaverygoodpractice.Italsoappliestosourcecontrolcommentsandkeepingdocumentationuptodate.

Readabilityalsoinvolveskeepingthingssimplebyonlymakingthemascomplexastheyneedtobeandnothidingfunctionalityinunnecessarylayersofabstraction.Forexample,notusingcleverprogrammingtechniquestoreducethefileline-countwhenastandardstructure(forexample,alooporifstatement)wouldbemorereadableandonlyslightlylonger.

Ithelpstohaveastandardwayofdoingthingsinyourteamtoavoidsurprises.Usingthesamemethodeverywherecanbemorevaluablethanfindingabetterwayofdoingit,andthenhavinglotsofdifferentways.Ifthereisconsensus,thenyoucangobackandretrofitthebettermethodeverywherewhereyouneedit.

Page 253: ASP.NET Core 1.0 High Performance

ComplexityreductionTherearevarioussolutionstomanagethecomplexitythatperformance-enhancingtechniquescanadd.Theseusuallyworkbyreducingtheamountoflogicthatyouneedtothinkaboutatanyonetimebyhidingthecomplications.

Oneoptionistouseframeworksthatstandardizehowyouwriteyourapplication,whichcanmakeiteasiertoreasonabout.Anotherapproachistouseanarchitecturethatallowsyoutoonlythinkaboutsmallpartsofyourcodebaseinisolation.Bybreakingupacomplexappintomanageablechunks,itbecomeseasiertoworkwith.

Note

ThisideaofmodularityisrelatedtotheSingleResponsibilityPrinciple(SRP),whichisthefirstoftheSOLIDprinciples(theothersareOpen/Closed,Liskovsubstitution,Interfacesegregation,andDependencyinversion).ItisalsosimilartothehigherlevelSeparationofConcerns(SoC)andtothesimplicityoftheUnixphilosophy.Itisbettertohavemanytoolsthateachdoonethingwell,ratherthanonetoolthatdoesmanythingsbadly.

Frameworks

Frontendframeworks,suchasReact(createdatFacebook),aredesignedtoreliablybuildwebapplicationviewsinJavaScript.Thesehelplargeteamsworkonaprojectbysimplifyingthedataflowandstandardizingtheapproach.

Tip

ReactcanbeintegratedwithASP.NETCoreusingtheReactJS.NETproject(reactjs.net).WecanuseReactNativetobuildcross-platformappsthatsharecodeacrossiOS,Android,andtheUniversalWindowsPlatform(UWP),targetingphone,desktop,andXbox(github.com/ReactWindows).There'salsoCodePushtoletyouliveupdateyourJavaScriptapps(includingCordova),withoutgoingthroughanappstore(microsoft.github.io/code-push).IfyouprefercodinginC#,thenyoucanbuildyourcross-platformmobileappswithXamarin(whichisnowfreeafterMicrosoftacquiredit).However,wewon'tgofurtherintoanyofthesetechnologiesinthisbook.

Onthebackend,wehavetheserver-sideframeworksof.NETCoreandASP.NETCore.AlongwithC#features,theseprovideconvenientwaysofsimplifyinghistorically-complicatedfeatures.Forexample,theasyncandawaitkeywordshidealotofthecomplicatedlogicassociatedwithasynchronousprogramming,andlambdafunctionsconciselyexpressintent.

Wecoveredmanyofthesefeaturesearlierinthisbook,sowewon'tgooverthemagainhere.Wealsohighlightedlibrariesthatcanmakeyourlifeeasierbyhidingboilerplatecodeforcomplexoperations,forexample,EasyNetQandRestBus.

Note

Page 254: ASP.NET Core 1.0 High Performance

Hidingacomplexprocessisneverperfect,andyouwilloccasionallycomeacrossabstractionsthatleaksomeoftheirimplementationdetail.Forexample,whenhandlingexceptions,youmayfindthattheissueyou'reinterestedinisnowwrappedinanaggregateexception.Ifyou'renotcareful,thenyourerrorlogsmaynolongercontainthedetailthatyoudesire.

Whatwehaveyettotalkaboutindetailisthearchitectureofawebapplication.Splittingamonolithicsystemupintodiscretepartscannotonlyimproveperformance,butifdoneright,itcanalsomakeiteasiertomaintain.

Architecture

Inthepreviouschapter,whendiscussingmessagequeuing,webrieflycoveredthemicroservicesarchitecture.ThisstyleisamoremodernreimaginingofthetraditionalServiceOrientedArchitecture(SOA),andalthoughusingreliableMQcommunicationispreferred,wecanalsoperformthiswithrepresentationalstatetransfer(RESTful)HTTPAPIs.

Typically,webuildatraditionalwebappasasingleapplicationormonolith.Thisiscommoniftheapphasgrownorganicallyoveranextendedperiodoftime,andthisisaperfectlyacceptablepractice.It'sapoordecisiontoover-engineertooearlybeforethereisanyneed,whichmaynevermaterialize.

Excessivepopularityisaniceproblemtohave,butdon'toptimizeforthisprematurely.Thisisn'tanexcusetomakethingsunnecessarilyslow,sobesuretounderstandthetradeoffsinvolved.

Tip

Usingamonolithicarchitectureisnotanexcusetobuildsomethingbadly,andyoushouldplanforexpansion,evenifyoudonotimplementitimmediately.Youcankeepthingssimplewhilestillallowingforfuturegrowth.

Althoughtheapplicationisasingleunit,youshouldsplitthecodebaseintowell-organizedmodules,whicharelinkedtogetherinasimple,logical,andeasy-to-understandway.RefertotheSOLIDprinciples,mentionedpreviously.

Ifamonolithicapplicationcan'teasilyscaletomeetuserdemandandisperformingpoorlyasaresult,thenyoucansplititupintosmallerseparateservices.Youmayalsowishtosplitanappupifithasbecometoocumbersometoiterateonquicklyanddevelopmentspeedhasslowed.

Monolithversusmicroservices

Thefollowingdiagramshowssomedifferencesbetweenatypicalmonolithandamicroservicesarchitecture:

Page 255: ASP.NET Core 1.0 High Performance

Here,theusermakesarequesttoanapplicationrunningonawebfarm.Wehaveomittedfirewalls,loadbalancers,anddatabasesforclarity,butmultiplewebserversareshowntoillustratethatthesamecodebaserunsonmultiplemachines.

Intheinitialmonolitharchitecture,theusercommunicatesdirectlywithasinglewebserver.Thisisideallyperrequest/responsepair.However,iftheapplicationwaspoorlydesignedandholdsstateinmemory,thenstickysessionsmaycausetheloadtopooloncertainservers.

Page 256: ASP.NET Core 1.0 High Performance

Thesecondexampleinthediagramofamicroservicesarchitectureisobviouslymorecomplicatedbutalsomoreflexible.Theuseragainsendsarequesttoawebserver,butinsteadofdoingallofthework,theserverputsamessageintoaqueue.

Theworkinthisqueueisdistributedbetweenmultiplebackendservicesofwhichthefirstoneisbusy,soasecondservicepicksupthemessage.Whentheservicecompletes,itsendsamessagetoanexchangeonthemessagebroker,whichusesapub/subbroadcasttoinformallofthewebservers.

Oneaddedpieceofcomplexityisthatthearchitectureshouldhavealreadysenttheresponsetotheuser'soriginalwebrequest,soyouneedtoconsidertheuserexperience(UX)morecarefully.Forexample,youcandisplayaprogressindicatorandupdatethestatusofthiswithanasynchronousWebSocketconnection.

Architecturecomparison

Themonolithapproachissimple,andyoucanjustaddmorewebserverstohandleadditionalusers.However,thisapproachcanbecomecumbersomeasanapplication(anddevelopmentteam)growslargerbecausetheslightestchangerequiresafullredeploymenttoeachwebserver.

Inaddition,amonolithiseasytoscalevertically(up)buthardtoscalehorizontally(out),whichwecoveredpreviously.However,amonolithiseasiertodebug,soyouneedtobecarefulandhavegoodmonitoringandlogging.Youdon'twantanyrandomoutageinvestigationtoturnintoamurdermysteryhuntbecauseofunnecessarilyimplementedmicroservices.

Note

Historically,FacebookhadadeploymentprocessthatconsistedofslowlycompilingtheirPHPcodebasetoagiganticgigabyte-scalebinary(forruntimeperformancereasons).TheythenneededtodevelopamodifiedversionofBitTorrenttoefficientlydistributethishugeexecutabletoalloftheirwebservers.Althoughthiswasimpressiveinfrastructureengineering,itdidn'taddresstherootcauseoftheirtechnicaldebtproblem,andtheyhavesincemovedontobettersolutions,suchastheHipHopVirtualMachine(HHVM),whichissimilartothe.NETCLR.

Ifyouwishtopracticecontinuousdeliveryanddeploymultipletimesaweek(orevenmanytimesaday),thenit'sadvantageoustobreakyourwebapplicationup.Youcanthenmaintainanddeployeachpartseparately,communicatingwitheachotherusingmessagesagainstanagreedAPI.

Thisseparationcanalsohelpyouuseagiledevelopmentmethodologies–forexample,usingmanysmallerteams—€”ratherthanbigteamsbecausesmallerteamsperformbetter.

Yourinstrumentofcontroltoscaleamonolithisverycrude,asallworkisdoneinoneplace.Youcan'tscalepartsofyourappindependentlytotheothercomponents.Youcanonlyscalethewholethingevenifthehighloadisconcentratedinasmallpart.Thisisanalogoustoacentralbankonlyhavingcontrolofasingleinterestrateasalever,whichaffectsmanythingsatonce.Ifyourappisdistributed,thenyouonlyneedtoscalethepartthatrequiresit,avoidingoverprovisioningand

Page 257: ASP.NET Core 1.0 High Performance

reducingcosts.

Awell-used(andoftenrephrased)quotefromAbrahamMaslowgoes:

"Isupposeitistempting,iftheonlytoolyouhaveisahammer,totreateverythingasifitwereanail."

Thisisknownasthelawoftheinstrumentandisrelatedtotheconfirmationbias.Ifyouonlyhaveonetool,thenyouarelikelytousethistoolforeverythingandonlyseethingsthatsupportyourexistingideas.Thiscommonlyappliestotoolsandframeworks,butitcanalsoapplytoscalingtechniques.

Thefirststeptowardsmodularitymaybetosplitabigwebapplicationintomanysmallerwebappssothatyoucandeploythemseparately.Thisstrategycanhavesomebenefits,butitalsohasmanylimitations.Somelogicmaybeunsuitabletohostinawebapp,forexample,long-runningprocesses,suchasthosemonitoringafilesystemorusedtomanipulatemedia.

Youmayalsofindthatyouneedtoduplicatecodethatwassharedintheoriginalmonolith.IfyouadheretotheDon'tRepeatYourself(DRY)doctrine,thenyoumightextractthisfunctionalitytoalibrary.Yet,nowyouhavedependenciesandversioningtomanage.You'llalsoneedprocessestobuild,packageandhostyourlibraryinaprivaterepository,allofwhichcanslowdowndevelopmentandreduceyouragility.

Note

Sometimes,wealsorefertoDRYasDuplicationIsEvil(DIE),andthisisthesensibleideathatanimplementationshouldonlyoccurinauniquelocation.Ifothercoderequiresthisfunctionality,thenitshouldcalltheoriginalfunctionandnothavecopiedcodepastedin.Thismeansthatyouonlyneedtomakeachangeinasingleplacetoapplyiteverywhere.

Amoreadvancedapproachistoextractfunctionalityintoaseparateservice,whichcanhandlemanydifferentwebapplications.Ifdesignedcorrectly,thenthisservicewon'tneedtohaveanyknowledgeoftheseappsandwillsimplyrespondtomessages.Thisallowsyoutoaddanewwebappwithoutmakingchangestothecodeofotherapplicationsorservices.

Refactoring

Refactoringamonolithintoservicescanbetrickyiftheapplicationhasbecomeatightly-coupledbig-ball-of-mud,butifit'sbeenwell-built(withplentyoftestcoverageandloosely-coupledcode),thenitshouldn'tbetootaxing.There'sabigdifferencebetweenawell-builtmonolithandabig-ball-of-mudmadewithlittlethought.

It'sworthexpandingontestcoverage,asunittestsareessentialforsuccessfulrefactoringwithoutintroducingregressionsornewbugs.Unittestsallowyoutorefactorandtidyupinconfidence,andtheypreventthecreationofcodethatisfragile,whichdevelopersareafraidtotouch.Wewillcovertestingingreaterdetail,includingautomation,inChapter9,MonitoringPerformance

Page 258: ASP.NET Core 1.0 High Performance

Regressions.

Bothofthesedesignpatternsmayappearsuperficiallysimilar,butinternally,it'sadifferentstory.Thefollowingdiagramillustratesthedifferencesbetweenawell-architectedmonolithandamessybig-ball-of-mud:

Thelargeboxesrepresentthecoderunningoneachwebserver(theWebServerNboxesfromthemonolithexampleintheearlierdiagram).Fromtheoutside,theylookthesame,butthedifferenceisintheinternalcouplingofthecode.

Page 259: ASP.NET Core 1.0 High Performance

Thebig-ball-of-mudisatangledmesswithcodereferencingotherfunctionsthroughouttheapplication.Themonolithiswell-structuredwithaclearseparationofconcernsbetweendifferentmodules.

Changestocodeinthebig-ball-of-mudcanhaveunexpectedsideeffectsbecauseotherpartsofitmayrelyontheimplementationdetailsofwhatyouaremodifying.Thismakesitbrittle,difficulttoalter,anddevelopersmaybeafraidoftouchingit.

Thewell-builtmonolithiseasytorefactorandsplitoutintoseparateservicesbecausethecodeisneatly-organized.Itusesabstractinterfacestocommunicatebetweenmodules,andcodedoesn'treachintoanotherclass'sconcreteimplementationdetails.Italsohasexcellentunittestcoverage,whichrunsautomatically.

Althoughbothareasinglecodebase,thequalityofthemonolithismuchhigherbecauseitiswell-distributedinternally.Gooddesignisimportantforfuture-proofing,aswebuildinandallowforexpansion.Themonolithhasn'tbeensplituptooearly(beforescalingwasrequired),butthedesignmakesthiseasytodolater.Incontrast,thebig-ball-of-mudhasaccumulatedalargeamountoftechnicaldebt,whichitneedstopayoffbeforewecanmakeanyfurtherprogress.

Tip

Technicaldebt(ortechdebtforshort)istheconceptofnotfinishingajoborcuttingcorners,whichcouldleadtomoredifficultiesuntilitispaidback.Forexample,failingtoproperlydocumentasystemwillmakealteringitlatermoredifficult.

Techdebtisnotnecessarilyabadthingifitisdeliberatelytakenoninfullknowledge,logged,andpaidbacklater.Forexample,waitingtowritedocumentationuntilafterareleasecanspeedupdelivery.However,techdebtthatisnotpaidbackorisaccumulatedwithoutknowledge(simplyduetosloppycoding),willgetworseovertimeandcausebiggerissueslater.

Thebestwaytodeliverahigh-qualityandflexibleapplication(that'seasytorefactor)istohaveacompetentandconscientiousdevelopmentteam.However,theseattributescanoftenbemoreaboutculture,communication,andmotivationthansimplyskillorrawtalent.Althoughthisisn'tabookaboutteammanagement,havingahealthycultureisveryimportant,sowe'llcoveralittleofthishere.Everyoneinanoperationsandsoftwaredevelopmentdepartmentcanhelpcreateapositiveandfriendlyculture,evenifyouusuallyneedbuy-infromhigherupaswell.

Tip

Toolsarealsoveryusefulinrefactoringandtesting.WecoveredtheVisualStudioIDEandReSharperpluginpreviously,buttherearemanymoretoolsfortesting.Wewillcovermoretestingtools,includingautomation,inChapter9,MonitoringPerformanceRegressions.

Page 260: ASP.NET Core 1.0 High Performance

AcultureofhighperformanceIfyouwanttoachievehighperformance,thenit'simportanttofosteracompanyculturethatencouragesthisandrecognizesperformanceasvital.Culturecan'tjustcomefromthebottomuponlyinvolvingengineers,italsoneedstocomefromthetop-downandmanagementmustbuyintotheperformanceprerogative.

Note

Thissectionisnotverytechnical,sofeelfreetoskipitifyoudon'tcareaboutmanagementorthehumansideofsoftwaredevelopment.

Page 261: ASP.NET Core 1.0 High Performance

AblamelesscultureThemostimportantattributesofahigh-performanceculturearethatitshouldbeopenandblameless.Everyoneneedstobefocusedonachievingthebestpossibleoutcomesthroughmeasuringandlearning.Attributingfaulttoindividualsistoxictodeliveringgreatsoftware,andthisisnotonlythecasewhenitcomestoperformance.

Ifsomethinggoeswrong,thenitisaprocessproblemandthefocusshouldbeonimprovingitandpreventingrepeatmistakesinthefuture,forexample,byautomatingit.Thisissimilartohowsafety-criticalindustries,suchasairtravel,behavebecausetheyrecognizethatblamingpeoplediscouragesthemfromraisingissuesearlybeforeadisasteroccurs.

ArelatedphilosophyistheJapaneseprocessofKaizen,whichencouragescontinuousimprovementbyeveryone.ThecarmanufacturerToyotapioneeredKaizenpracticestoimprovetheefficiencyoftheirproductionline,andmostautomotivecompaniesandmanyotherdifferentindustrieshavesinceadoptedthem.

Someindustriesalsohaveprocessestoencouragewhistle-blowingthatprotecttheindividualsraisingconcerns.However,ifthisisrequiredinwebapplicationdevelopment,thenit'sasuresignthatthecultureneedswork.Developersshouldfeelthattheyareabletodirectlyraiseconcernsbypassingtheirlinemanagerwithoutconsequence.Ifeveryone'sopinionisrespected,thenthisshouldn'tevenbenecessary.

Page 262: ASP.NET Core 1.0 High Performance

IntellectualdishonestyIfteammembersgetdefensivewhenideasarechallenged,thenthisisasignthatthingsmaynotbeworkingwell.Everybodymakesmistakesandhasgapsintheirknowledge,atruththebestengineersembrace.Youshouldstriveforaculturewhereeveryoneisopentonewideasandisalwaysaskingquestions.

Ifpeopleareunabletoacceptconstructivecriticismandhavetheirideaschallenged,thentheymaylackconfidenceandbecoveringupalackofcompetence.Experienceddevelopersknowthatyouneverstoplearning,theyadmittheirignoranceandarealwaysopentooffersofimprovements.

Beingclosedtosuggestionsaltersthebehaviorofothers,andtheywillstopraisingsmallissuesearly.Thisresultsinopensecretsaboutpoorquality,andthefirstthatisknownaboutaproblemisatreleasetime,atwhichpointeverythingismuchworse(oronfire).

Thisisnotanexcusetobenastytopeople,soalwaystrytobeniceandgentlyexplainthereasonsbehindyourcriticism.It'seasytofindfaultinanything,soalwaysproposeanalternativeapproach.Ifyouarepatient,thenareasonablepersonwillbegratefulforthelearningopportunityandappreciategainingexperience.

Agoodruletofollowis"don'tbeajerk"andtreatothersasyouwouldliketobetreated,sobekindandthinkabouthowyouwouldfeelifthesituationwasreversed.Justrememberthatbeingniceisnotalwayscompatiblewithdoingtherightthing.

Alittleself-deprecationcangoalongwaytomakingyoumoreapproachable,ratherthansimplydictatingtheone-true-way.However,youshouldmakeitclearwhensomethingisajokeortongueincheek,especiallywhendealingwithculturesthataremoredirectorwhencommunicatingtextually.

Forexample,NorthAmericansareoftenlesssubtlethanandnotassarcasticastheBritish(whoalsospellsomeworddifferently,andsomewouldsaymorecorrectly).Obviously,useyourownjudgmentbecausethismaybeterribleadviceandcouldcauseoffenseor,evenworse,afull-ondiplomaticincident.Hopefully,itisself-evidentthatthiswholeparagraphistongueincheek.

Peoplewhohaveintegrityandconfidenceintheirideascanaffordtobemodestandself-deprecating,butinternalcompanyculturecaninfluencethistoo.Aparticularlybadpracticeistoconductperformancereviewsbyladdering(alsoknownasstackranking),whichinvolvesputtingeveryoneinorder,relativetoeverybodyelse.Thisistoxicbecauseitrewardspeoplewhofocusmoreonmarketingthemselvesthanthosewhorecognizethedeficienciesintheirtechnicalskillsandtrytoimprovethem.Inthepathologicalcase,allofthebestpeopleareforcedout,andyouendupwithacompanyfullofsociopathicsharpsuits,whoaretechnicallyilliterateorevenmorallybankrupt.

Page 263: ASP.NET Core 1.0 High Performance

SlowdowntogofasterSometimes,thecompanymustallowthedevelopmentteamtoslowdownonfeaturedeliveryinordertofocusonperformanceandresolvingtechnicaldebt.Theyshouldbegiventimetobethoughtfulaboutdesigndecisionssothattheycancogitateavoidingprematuregeneralizationorcarelessoptimization.

Performanceisasignificantsellingpointofsoftware,anditismucheasiertobuildqualitythroughoutthedevelopmentprocessthaninapolishingphaseattheend.ThereisasignificantbodyofevidencethatsuggeststhatgoodperformanceimprovesReturnonInvestment(RoI)andcreatescustomers.Thisisespeciallytrueontheweb,wherepoorperformancedecreasesconversionrateandsearchengineranking.

Havingahealthycultureisnotonlyimportantfortheruntimeperformanceofyoursoftwarebutalsoforthespeedatwhichyoucandevelopit.Theteamshouldbeencouragedtobehaverigorouslyandwriteprecise,butalsoconcise,code.

Yougetwhatyoumeasure,andifyouonlymeasuretherateoffeaturedelivery,orevenworsesimplyLinesofCode(LoC)written,thenqualitywillsuffer.Thiswillhurtyouinthelongrunandisafalseeconomy.

Falseeconomiesarewhenyoumakeshorttermcostsavingmeasuresthatactuallyloseyoumoremoneyinthelongterm.Examplesofthisareskimpingonhardwarefordevelopersorinterruptingsomeoneinthemiddleofcodingwithsomethingtrivial,whichcouldeasilywaituntillater,andforcingthemtoswitchcontexts.

Anothernonsoftwareexampleisashortsightedgovernmentmakingcutstoinvestmentinresearchbysacrificinglong-termgrowthforshort-termgain,possiblyduetothelackofanylong-termeconomicplan.

Note

Hardwareissignificantlycheaperthandevelopertime.Therefore,ifeveryoneonyourteamdoesn'thaveabeefyboxandmultiplemassivemonitors,thenproductivityisbeingneedlesslydiminished.Evenoveradecadeago,Facebook'ssoftwaredeveloperjobadvertslisteddual24-inchwidescreenmonitorsasaperk.

Page 264: ASP.NET Core 1.0 High Performance

FromthegroundupInahealthyandprogressiveculture,itcanbetemptingtorewritepoorqualitysoftwarefromscratch,perhapsinthelatesttrendyframework,butthisisusuallyamistake.Releasedsoftwareisbattle-hardened(nomatterhowbadlyitwasbuilt),andifyourewriteit,thenyouwillprobablymakethesamemistakesagain,forexample,re-implementingbugsthatyoualreadypatched.Thisisespeciallytrueifthesoftwarewasnotbuiltwithgoodunittestcoverage,whichcanhelppreventregressions.

Theonlycasewhereyoucouldreasonablyrewriteanapplicationfromthegroundupisifyouhaddeliberatelymadeaprototypetoexploretheproblemspacewiththesoleintentionofthrowingitaway.However,youshouldbeverycarefulbecauseifyou'veactuallybuiltaMinimumViableProduct(MVP)instead,thenthesehaveahabitofstickingaroundforalongtimeandformingthefoundationsoflargerapplications.

Abetterapproachtoafullrewriteistoaddteststotheapplication(ifitdoesn'talreadyhavethem)andgraduallyrefactorittoimprovethequalityandperformance.Ifyoubuiltanapplicationinsuchawayastomakeitdifficulttounittest,thenyoucanstartwithUserInterface(UI)tests,perhapsusingaheadlesswebbrowser.Wewillcovertestingmore,includingperformancetesting,inthenextchapter.

Page 265: ASP.NET Core 1.0 High Performance

SharedvaluesCultureisreallyjustasetofsharedvalues–thingssuchasopenness,sustainability,inclusivity,diversity,andethicalbehavior.Itcanhelphavingthesevaluesformallydocumentedsothateveryoneknowswhatyoustandfor.

Youmayhaveaprogressiveopensalarypolicysothatotherscan'tusesecretearninginformationasatooltopaypeopleless.However,thiswouldneedtoapplyuniversally,asit'sunhealthytohavemultipleconflictingculturesbecausethiscanprecipitateanus-versus-themattitude.

There'splentymoretosayaboutculture,but,asyoucansee,therearemanycompetingconcernstobalance.Themostimportantideaistomakeintentionalandthoughtfultradeoffs.Thereisn'tonecorrectchoice,butyoushouldalwaysbeconsciousoftheconsequencesandappreciatehowtinyactionscanalterteamperformance.

Page 266: ASP.NET Core 1.0 High Performance

ThepriceofperformanceDevelopersshouldhaveanideaoftheavailablebudgetforperformanceandunderstandthecostofthecodethattheywrite,notjustinexecutionthroughputbutinreadability,maintainability,andpowerefficiency.Throwingmorecoresataunitofworkisnotnearlyasgoodasrefactoringittobesimpler.

Efficiencyhasbecomeincreasinglyimportant,especiallywiththeriseofmobiledevicesandcloudcomputingtime-basedusagebilling.Parallelizinganinefficientalgorithmmaysolveaperformanceprobleminthetimedomain,butit'sacrudebrute-forceapproachandalteringtheunderlyingimplementationmaybebetter.

Lessisoftenmoreandsometimesdoingnothingisthebestapproach.Softwareengineeringisnotonlyaboutknowingwhattobuildbutwhatnottobuild.Keepingthingssimplehelpsothersonyourteamuseyourwork.Youshouldaimtoavoidsurprisinganyonewithnonobviousbehavior.Forexample,considerthatyoubuildanAPIandthengiveitconventionaldefaults;ifthiscouldpotentiallytakealongtime,thenmakethemethodsasynchronoustoindicatethisfact.

Youshouldaimtomakeiteasytosucceedandhardtofailwhenbuildingonyourcode.Makeitdifficulttodothewrongthing,forexample,ifamethodisunsafe,nameittodocumentthisfact.Beingacompetentprogrammerisonlyasmallpartofbeingagooddeveloper,youalsoneedtobehelpfulandproficientatcommunicatingclearly.

Infact,beinganexpertprogrammercanbeadownsideifyoudon'tdeliberatelykeepthingssimpletoaidtheunderstandingofothersonyourteam.Youshouldalwaysbalanceperformanceimprovementsagainstthesideeffects,andyoushouldn'tmakethemattheexpenseoffuturedevelopmentefficiencywithoutgoodreason.

Page 267: ASP.NET Core 1.0 High Performance

DistributeddebuggingDistributedsystemscanmakeitdifficulttodebugproblems,andyouneedtoplanforthisinadvancebyintegratingtechnologythatcanhelpwithvisibility.Youshouldknowwhatmetricsyouwanttomeasureandwhatparametersareimportanttorecord.

Asyourunawebapplication,itisn'tacaseofdeployandforgetasitmightbewithmobileappsordesktopsoftware.Youwillneedtokeepaconstantautomatedeyeonyourapplicationtoensurethatitisalwaysavailable.Ifyoumonitorthecorrectperformancemetrics,thenyoucangetearlywarningsignsofproblemsandcantakepreventativeaction.Ifyouonlymeasureuptimeorresponsiveness,thenthefirstthatyoumayknowofaproblemisanoutagenotification,probablyatanunsociablehour.

Youmayoutsourceyourinfrastructuretoacloud-hostingcompanysothatyoudon'thavetoworryabouthardwareorplatformfailures.However,thisdoesn'tcompletelyabsolveyouofresponsibilityandyoursoftwarewillstillneedcontinuousmonitoring.Youmayneedtoarchitectyourapplicationdifferentlytoworkinharmonywithyourhostingplatformandscaleorself-healwhenissuesarise.

Ifyoudesignyoursystemcorrectly,thenyourwebapplicationwillrunitself,andyou'llrarelygetnotifiedofactionsthatrequireyourattention.Ifyoucansuccessfullyautomateallofthethings,ratherthanbabysittingalivedeployment,thenthat'smoretimeyoucanusetobuildthefuture.

Inadistributedarchitecture,youcan'tsimplyattachadebuggertothelivewebserver,notthatthisisagoodideaevenwhenpossible.Thereisnoliveserveranymore,therearenowmanyliveserversandevenmoreprocesses.Togetaholisticpictureofthesystem,youwillneedtosimultaneouslyexaminethestateofmultiplemodules.

Therearemanytoolsthatyoucanusetohelpwithcentralizingyourdebuginformation.Youcanretrofitsomeofthem.However,togetthemostoutofthem,youshoulddecidewhattomeasureupfrontandbuildtelemetrycapabilitiesintoyoursoftwarefromthestart.

Page 268: ASP.NET Core 1.0 High Performance

LoggingLoggingisvitaltoahigh-performanceapplication,sowhileitistruethatloggingaddssomeoverheadandcanslowdownexecution,omittingitwouldbeshort-sightedandafalseeconomy.Withoutlogging,youwon'tknowwhatisslowandrequiresimprovement.Youwillalsohaveotherconcerns,suchasreliability,forwhichloggingisessential.

Errorlogging

Youmayhaveused(oratleastbefamiliarwith)theexcellentASP.NETpackagecalledErrorLoggingModulesandHandlers(ELMAH)tocatchunhandledexceptions(elmah.github.io).ELMAHisgreatforalreadyexistingapplications,asyoucandropitintoaliverunningwebapp.However,it'spreferabletohaveerrorloggingbuiltintoyoursoftwarefromthestart.

Unfortunately,ASP.NETCoredoesnotsupportELMAH,butthereisasimilarpackagecalledErrorLoggingMiddleware(ELM).AddingthistoyourwebapplicationisjustassimpleasinstallingGlimpse,butitisreallyjustaprototypeanddoesn'thaveallthefeaturesofELMAH.First,addtheMicrosoft.AspNetCore.Diagnostics.ElmNuGetpackagetoyourproject,asshowninthefollowingimage:

Then,intheConfigureServicesmethodoftheStartupclass,addthefollowinglineofcode:

services.AddElm();

YoualsoneedtoaddthefollowinglinestotheConfiguremethodofthesameclass:

Page 269: ASP.NET Core 1.0 High Performance

app.UseElmPage();

app.UseElmCapture();

Tip

Tostartwith,youmaywanttoputtheseintheenv.IsDevelopment()ifstatementsothattheyareonlyactiveonyourworkstation.IfyouuseELMonproduction,thentheselogswilldefinitelyneedsecuring.

Youcannowvisitthe/Elmpathofyourwebapplicationinyourbrowsertoseethelogs,asshowninthefollowingimage.Usethesearchboxtofilterresults,clickonvattheendofeachline(notshown)toexpandtheentry'sdetails,andclickon^tocollapseitagain:

Page 270: ASP.NET Core 1.0 High Performance

Note

WhenusingELM,ELMAH,oreventhedefaulterrorpages,youshouldbecarefultonotshowdetailedexceptionsorstacktracestorealusers.Thisisn'tsimplybecausethey'reunfriendlyandunhelpful,theyareagenuinesecurityconcern.Errorlogsandstacktracescanrevealtheinternalworkingsofyourapplication,whichmaliciousactorscanexploit.

ELMisfairlybasic,butitcanstillbeuseful.However,therearebettersolutionsalreadybuiltintothedefaulttemplates–things,suchastheintegratedsupportforloggingandApplicationInsights.

ApplicationInsights

ApplicationInsightsallowsyoutomonitortheperformanceofyourapplicationandviewrequestsorexceptions.YoucanuseitwithAzure,butitwillalsoworklocallywithoutneedinganAzureaccount.YoucaneasilyenableApplicationInsightsbykeepingtherelevantcheckboxticked,asshowninthefollowingimage,whenyoucreateanewASP.NETCorewebapplicationprojectinVisualStudio,andyoudon'tneedtosignintoAzuretodothis:

Tip

TheApplicationInsightstemplateoptionisonlyavailableundertheWebtemplatesnotthe.NETCoretemplates.

Buildandrunthenewproject,thenopentheApplicationInsightsSearchwindowtoseetheoutput.Navigatearoundthewebappinyourbrowser,andyouwillseerecordsstarttoappear,whichshouldlooksomethinglikethefollowing:

Page 271: ASP.NET Core 1.0 High Performance

Tip

Ifyoudon'tseeanyrecordsintheoutput,thenyoumayneedtoupdatetheNuGetpackage(Microsoft.ApplicationInsights.AspNetCore)orclickontheSearchicon.

Youcanfilterbyeventtype,forexample,requestsorexceptions,andtherearemoredetailedfilterstorefineyoursearch.Youcanselectanindividualrecordtoseemoredetails,whichwilllooksomethinglikethefollowing:

Page 272: ASP.NET Core 1.0 High Performance

AlthoughyoucanaccessthisinformationlocallywithoutAzure,youcanchoosetoselectConfigureApplicationInsightsandsetuploggingofdatatoyourAzureaccount.

Page 273: ASP.NET Core 1.0 High Performance

Ifyouknowwhatyou'redoing,thenyoucanuseAdvancedModeandenteryourSubscriptionIDandInstrumentationKeymanually:

Note

Secretconfigurationinformation,suchasthis,isnowstoredoutsideofthesourcetreetohelppreventitleaking.Youcannowdefinesecretsasenvironmentvariablesorinasecretsstoreheldinyouruserprofile.

OnceyousetupAzure,thenyoucanviewthetelemetryresultsonlineandaggregateinformationfrommanydiversesystems.Wedon'thavespacetocoverthisinmoredetailhere,butyoucanfindmoreinformationonlineatazure.microsoft.com/en-us/documentation/services/application-insights.

Integratedlogging

LoggingisnowbuiltintoASP.NETCore(intheMicrosoft.Extensions.Loggingpackage)aswellasDependencyInjection(DI),andbothareincludedinthedefaulttemplates.Thisreduces

Page 274: ASP.NET Core 1.0 High Performance

thebarriertoentry,andit'snowtrivialtousethesehelpfultechnologiesineventhesmallestofprojects.

Previously,youwouldhavetoaddloggingandDIlibrariesbeforeyoustarted,whichcouldputmanypeopleoffusingthem.Ifyoudidn'talreadyhaveastandardchoiceforboth,thenyouwouldneedtowadethroughtheplethoraofprojectsandresearchthemeritsofeach.

Tip

Youcanstilluseyourpreferredlibrariesifyouarealreadyacquaintedwiththem.It'sjustthattherearenowsensibledefaults,whichyoucanoverride.

LoggingisconfiguredintheStartupclass,andifyouusethestandardwebapplicationtemplate,thenthiswillalreadybeincludedforyou.Theloggerfactoryreadssettingsfromtheappsettings.jsonfile.Inhere,youcanconfigurethelogginglevel,andbydefault,therelevantsectionlookslikethefollowing:

"Logging":{

"IncludeScopes":false,

"LogLevel":{

"Default":"Debug",

"System":"Information",

"Microsoft":"Information"

}

}

Thissetsaverychattyloglevel,whichisusefulfordevelopment,butyouwillprobablywanttoonlylogwarnings,anderrorswhenyourunthisinproduction.

Note

AlongwithApplicationInsightsandlogging,usefuldebuggingtoolsincludedbydefaultintheStartupclassincludeadeveloperexceptionpage,whichislikeanadvancedversionoftheoldYellowScreenOfDeath(YSOD)ASP.NETerrorpage.Alsoincludedisadatabaseerrorpage,whichcanhelpfullyapplyEFmigrationsandmitigatesacommonpitfallofpreviousEFcode-firstmigrationdeployments.

ToaddtheloggertoyourMVChomecontrollerviaconstructorinjection,youcanusethefollowingcode(afteraddingusingMicrosoft.Extensions.Logging;toyourusingstatementsatthetopofthefile):

privatereadonlyILoggerLogger;

publicHomeController(ILoggerFactoryloggerFactory)

{

Logger=loggerFactory.CreateLogger<HomeController>();

}

Afterthis,youcanuseLoggertologeventsinsideactionmethods,asfollows:

Logger.LogDebug("Homepageloaded");

Page 275: ASP.NET Core 1.0 High Performance

Therearemanymorelogginglevelsavailableandoverloadedmethodssothatyoucanlogadditionalinformation,forexample,exceptions.Wewon'tgointoanymoredetailhere,butyoudon'tsimplyhavetologtextevents,youcanalsorecordexecutiontimes(perhapswithastopwatch)orincrementcounterstoseehowoftencertaineventsoccur.Next,we'llseehowtoviewthesenumberscentrallyandreadthemcorrectly.

Note

Formoreexamplesofhowtouselogging,youcanexaminethedefaultaccountcontroller(ifyouincludedindividualuseraccountsauthenticationinthetemplate).Formoreinformation,youcanreadthedocumentationatdocs.asp.net/en/latest/fundamentals/logging.html.

Centralizedlogging

Loggingisgreat.However,inadistributedsystem,youwillwanttofeedallofyourlogsandexceptionsintoasinglelocation,whereyoucaneasilyanalyzethemandgeneratealerts.OnepotentialoptionforthisisLogstash(elastic.co/products/logstash),whichwefleetinglymentionedinChapter2,MeasuringPerformanceBottlenecks.

Ifyoupreferamoremodularapproachandwanttorecordperformancecountersandmetrics,thenthereisStatsD,whichlistensforUDPpacketsandpushestoGraphiteforstorageandgraphing.Youcangetitatgithub.com/etsy/statsdandthereareafew.NETclientslistedonthewiki,alongwithexampleC#codeinthemainrepository.

Youmaywishtousemessagequeuingforloggingsothatyoucanquicklyputaloggedeventintoaqueueandforgetaboutit,ratherthandirectlyhittingaloggingserver.IfyoudirectlycallanAPI(andaren'tusingUDP),thenmakesurethatit'sasynchronousandnonblocking.Youdon'twanttoslowdownyourapplicationbylogginginefficiently.

Therearealsocloudoptionsavailable,althoughtheusualcaveatsaboutlock-inapply.AWShasCloudWatch,whichyoucanreadmoreaboutataws.amazon.com/cloudwatch.AzureDiagnosticsissimilar,andyoucanintegrateitwithApplicationInsights,readmoreatazure.microsoft.com/en-us/documentation/articles/azure-diagnostics.

Thereareothercross-platformcloudservicesavailable,suchasNewRelicorStackify,butthesecanbequiteexpensive,andyoumaywishtokeepyourloggingwithinyourowninfrastructure.Youcouldshoehornthedataintoanalyticssoftware,suchasGoogleAnalyticsortheprivacy-focusedPiwik(whichisopensourceandcanbeself-hosted),butthesearelesssuitablebecausethey'redesignedforaslightlydifferentpurpose.

Page 276: ASP.NET Core 1.0 High Performance

StatisticsWheninterpretingyourcollectedmetrics,ithelpstoknowsomebasicstatisticsinordertoreadthemcorrectly.Takingasimplemeanaveragecanmisleadyouandmaynotbeasimportantassomeothercharacteristics.

Wheninstrumentingyourcodetocollectmetadata,youshouldhavearoughideaofhowoftenparticularloggingstatementswillbecalled.Thisdoesn'thavetobeexact,andaroughorderofmagnitudeapproximation(orFermiestimate)willusuallysuffice.

Thequestionyoushouldtrytoanswerishowmuchofthedatashouldbecollected,allofitorarandomsample?Ifyouneedtoperformsampling,thenyoushouldcalculatehowbigthesamplesizeshouldbe.WecoveredsamplinginrelationtoSQLinChapter5,OptimizingI/OPerformance,andtheideaissimilarhere.Performancestatisticsrequirethesamelevelofrigorasbenchmarkingdoes,andyoucaneasilybemisledordrawincorrectconclusions.

StatsDincludesbuilt-insupportforsampling,buttherearemanyotherapproachesavailableifyouwanttoinvestigatethem.Forexample,onlinestreamingalgorithmsandreservoirsaretwooptions.Theimportantthingtokeepinmindforperformanceistouseafastrandomnumbergenerator(RNG).As,forsampling,thisdoesn'tneedtobecryptographicallysecure,apseudorandomnumbergenerator(PRNG)isfine.In.NET,youcanusenewRandom()foraPRNG,ratherthanthemoresecureoptionofRandomNumberGenerator.Create().SeeChapter6,UnderstandingCodeExecutionandAsynchronousOperations,formoreexamplesofhowtousebothofthese.

Whenlookingatyourresults,theoutliersmaybemoreinterestingthantheaverage.Althoughthemedianismorevaluablethanthemean,inthiscase,youshouldreallylookatthepercentiles,forexample,the90th,95th,and99thpercentiles.Thesedatapointscanrepresentonlyasmallfractionofyourdata,butatscale,theycanoccurfrequently.Youwanttooptimizefortheseworstcasescenariosbecauseifyourusersexperiencepagesloadstakingoverfivesecondstenpercentofthetime(eventhoughtheaveragelooksfast),thentheymaygoelsewhere.

There'smuchmoretosayonstatistics,butbeyondthebasics,therearediminishingreturns.Ifyourmathisrusty,thenitisprobablywisetohavearefresher(Wikipediaisgreatforthis).Then,youcanexploresomemoreadvancedtechniques,forexample,thehigh-performanceHyperLogLog(HLL)algorithm,whichcanestimatethesizeofalargesetofelementsusingverylittlememory.RedissupportstheHLLdatastructure(withthePFADD,PFCOUNT,andPFMERGEcommands).Formoreondifferentdatastructures,refertoChapter6,UnderstandingCodeExecutionandAsynchronousOperations.

Note

Thisisonlyabriefintroductiontoperformancelogging,butthereismuchmoreforyoutoexplore.Forexample,ifyouwanttostandardizeyourapproach,thenyoucanlookintoAPDEX(apdex.org),whichsetsastandardmethodtorecordtheperformanceofapplicationsandcompute

Page 277: ASP.NET Core 1.0 High Performance

scores.

Page 278: ASP.NET Core 1.0 High Performance

ManagingstalecachesIt'sworthprovidingaquickremindertostillconsidersimpleissuesafterallofthiscomplexity.Itisfartooeasytogetlostinthedetailsofacomplicatedbugorperformancetweakandmisstheobvious.

Tip

Agoodtechniquetohelpwiththisisrubberduckdebugging,whichgetsitsnamefromtheprocessofexplainingyourproblemtoarubberduckonyourdesk.Mostofushaveexperiencedsolvingaproblemafteraskingforhelp,eventhoughtheotherpersonhasn'tsaidanything.Theprocessofexplainingtheproblemtosomeone(orsomething)elseclarifiesit,andthesolutionbecomesobvious.

Ifsomethingappearstonotbeworkingafterafix,thenchecksimplethingsfirst.Seewhetherthepatchhasactuallybeendeliveredanddeployed.Youmaybeseeingstalecodefromacacheinsteadofyournewversion.

Whenmanagingcaches,versioningisausefultooltohelpyouidentifystaleassets.Youcanalterfilenamesoraddcommentstoincludeauniqueversionstring.ThiscanbeSematicVersioning(SemVer),anISOdateandtimestamp,orahashofthecontents.Formoreoncachebusting,refertoChapter7,LearningCachingandMessageQueuing.

Note

SemVer,isagreatwaytoversionyourcodebecauseitimplicitlycapturesinformationoncompatibilityandbreakingchanges.YoucanreadmoreaboutSemVeratsemver.org.

Page 279: ASP.NET Core 1.0 High Performance

SummaryInthischapter,wesawhowtherearealwaysdownsidestoeverydecisionandeverychoicehasacostattachedbecausenothingcomesforfree.Therearealwaystradeoffsinvolved,andyouneedtobeawareoftheconsequencesofyouractions,whichmaybesmallandsubtle.

Thekeylessonistotakeathoughtfulandrigorousapproachtoaddinganyperformance-enhancingtechnique.Measurementiscrucialtoachievingthis,butyoualsoneedtoknowhowdatacanmisleadyouifyoucollectorinterpretitincorrectly.

Inthenextchapter,wewillcontinuewiththemeasurementthemeandlearnhowtouseteststomonitorforperformanceregressions.Youwillseehowtousetesting(includingunittesting),automation,andcontinuousintegrationtoensurethatonceyousolveaperformanceproblem,itstaysthisway.

Page 280: ASP.NET Core 1.0 High Performance

Chapter9.MonitoringPerformanceRegressionsThischapterwillcoverwritingautomatedteststomonitorperformancealongwithaddingthesetoaContinuousIntegration(CI)anddeploymentsystem.Byconstantlycheckingforregressions,you'llavoidaccidentallybuildingaslowapplication.We'llalsocoverhowtosafelyloadtestasystemwithoutforcingitofflineandhowtoensurethattestsmimicreallifeusageasfaraspossible.

Topicscoveredinthischapterincludethefollowing:

ProfilingLoadtestingAutomatedtestingPerformancemonitoringContinuousintegrationanddeploymentRealisticenvironmentsandproduction-likedataUItestingwithseleniumandphantomheadlessbrowsersA/BtestingforconversionoptimizationCloudservicesandhostingDevOps

Youwillseehowtoautomateperformancemonitoringandtestingsothatyoudon'tneedtoremembertokeepdoingitmanually.You'lllearnhowtocatchregressionsearlybeforetheycausetroubleandhowtosafelybackthemoutforrework.

Page 281: ASP.NET Core 1.0 High Performance

ProfilingandmeasurementWestartedthisbookbyhighlightingtheimportanceofmeasurementandprofilingbycoveringsomesimpletechniquesinChapter2,MeasuringPerformanceBottlenecks.Wecontinuedthisthemethroughout,andwe'llendthebookonitaswellbecauseit'simpossibletooverstatehowimportantmeasuringandanalyzingreliableevidenceis.

Previously,wecoveredusingGlimpsetoprovideinsightsintotherunningofyourwebapplication.WealsodemonstratedtheVisualStudiodiagnosticstoolsandtheApplicationInsightsSoftwareDevelopmentKit(SDK).There'sanothertoolthat'sworthmentioningandthat'sthePrefixprofiler,whichyoucangetatprefix.io.

Prefixisafreeweb-basedASP.NETprofilerthatsupportsASP.NETCore.However,itdoesn'tsupport.NETCoreyet(althoughthisisplanned),soyou'llneedtorunASP.NETCoreon.NETFramework4.6fornow.There'salivedemoontheirwebsite(atdemo.prefix.io)ifyouwanttoquicklycheckitoutanditlookslikethefollowing:

Page 282: ASP.NET Core 1.0 High Performance

Note

ASP.NETCorecanrunontopofeither.NETCoreortheexistingstableframework.Forarefresheronhoweverythingfitstogether,referbacktoChapter1,WhyPerformanceIsaFeature,orformoredetails,refertoChapter6,UnderstandingCodeExecutionandAsynchronousOperations.

YoumayalsowanttolookatthePerfViewperformanceanalysistoolfromMicrosoft,whichisusedinthedevelopmentof.NETCore.YoucandownloadPerfViewfrommicrosoft.com/download/details.aspx?id=28567asaZIPfilethatyoucanjustextractandrun.Itisusefultoanalyzethememoryof.NETapplicationsamongotherthings,anditlookslikethiswhenyoulaunchit:

Page 283: ASP.NET Core 1.0 High Performance

YoucanusePerfViewformanydebuggingactivities,forexample,totakeasnapshotoftheheaporforceGCruns.Wedon'thavespaceforadetailedwalkthroughhere,buttheincludedinstructionsaregood,andthereareblogsonMSDNwithguidesandmanyvideotutorialsonChannel9atchannel9.msdn.com/Series/PerfView-Tutorialifyouneedmoreinformation.

Tip

Sysinternalstools(technet.microsoft.com/sysinternals)canalsobehelpful,butastheydonotfocusmuchon.NET,theyarelessusefulinthiscontext.

Whiletoolssuchasthesearegreat,whatwouldbeevenbetteristobuildperformancemonitoringintoyourdevelopmentworkflow.Automateeverythingthatyoucan,andthismakesperformancecheckstransparent,routine,andrunbydefault.

Manualprocessesarebadbecauseyoucanskipsteps,andyoucaneasilymakeerrors.Youwouldn'tdreamofdevelopingsoftwarebye-mailingfilesaroundoreditingcodedirectlyonaproductionserver,sowhynotautomateyourperformanceteststoo.

Page 284: ASP.NET Core 1.0 High Performance

Changecontrolprocessesexisttoensureconsistencyandreduceerrors.ThisiswhyusingaSourceControlManagement(SCM)system,suchasGitorTeamFoundationServer(TFS)isessential.It'salsoextremelyusefultohaveabuildserverandperformCIorevenfully-automateddeployments.

Note

Sourcecontrolallowsmultiplepeopletoworkonafilesimultaneouslyandmergethechangeslater.It'slikeWord'strackchangesfeature,butactuallyusable.Weassumethatwe'repreachingtotheconvertedandyoualreadyusesourcecontrol.Ifnot,stopreadingrightnowandgoinstallanSCMsystem.

Ifthecodedeployedinproductiondiffersfromwhatyouhaveonyourlocalworkstation,thenyouhaveverylittlechanceofsuccess.ThisisoneofthereasonswhySQLStoredProcedures(SPs/sprocs)aredifficulttoworkwith,atleastwithoutrigorousversioncontrol.It'sfartooeasytomodifyanoldversionofanSPonadevelopmentDB,accidentallyrevertabugfix,andendupwitharegression.IfyoumustuseSPs,thenyouwillneedaversioningsystem,suchasReadyRoll(whichRedgatehasnowacquired).

Asthisisn'tabookonContinuousDelivery(CD),wewillassumethatyouarealreadypracticingCIandhaveabuildserver,suchasJetBrainsTeamCity,ThoughtWorksGoCD,CruiseControl.NET,oracloudservice,suchasAppVeyor.Perhapsyou'reevenautomatingyourdeploymentsusingatool,suchasOctopusDeploy,andyouhaveyourowninternalNuGetfeeds,usingsoftwaresuchasTheMotleyFool'sKlondike,oracloudservice,suchasMyGet(whichalsosupportsnpm,bower,andVSIXpackages).

Tip

NuGetpackagesareagreatwayofmanaginginternalprojects.InnewversionsofVisualStudio,youcanseethesourcecodeofpackagesanddebugintothem.Thismeansnomorehugesolutionscontainingaludicrousnumberofprojects.

Bypassingprocessesanddoingthingsmanuallywillcauseproblems,evenifyouarefollowingascript.Ifitcanbeautomatedthenitprobablyshouldbe,andthisincludestesting.

Page 285: ASP.NET Core 1.0 High Performance

TestingTestingisessentialtoproducinghigh-qualityandwell-performingsoftware.Thesecrettoproductivetestingistomakeiteasy,reliable,androutine.Iftestingisdifficultortestsregularlyfailbecauseofissuesunrelatedtothesoftware(forexample,environmentalproblems),thentestswillnotbeperformedortheresultswillbeignored.Thiswillcauseyoutomissgenuineproblemsandshipbugsthatyoucouldhaveeasilyavoided.

Therearemanydifferentvarietiesoftesting,andyoumaybefamiliarwiththemorecommoncasesusedforfunctionalverification.Inthisbook,wewillmainlyfocusontestspertainingtoperformance.However,theadvicehereisapplicabletomanytypesoftesting.

Page 286: ASP.NET Core 1.0 High Performance

AutomatedtestingAspreviouslymentioned,thekeytoimprovingalmosteverythingisautomation.Teststhatareonlyrunmanuallyondeveloperworkstationsaddverylittlevalue.Ofcourse,itshouldbepossibletorunthetestsondesktops,butthisshouldn'tbetheofficialresultbecausethere'snoguaranteethattheywillpassonaserver(wherethecorrectfunctioningmattersmore).

Tip

Althoughautomationusuallyoccursonservers,itcanbeusefultoautomateteststhatrunondeveloperworkstationstoo.OnewayofdoingthisinVisualStudioistouseaplugin,suchasNCrunch.Thisrunsyourtestsasyouwork,whichcanbeveryusefulifyoupracticeTest-DrivenDevelopment(TDD)andwriteyourtestsbeforeyourimplementations.YoucanreadmoreaboutNCrunchandseethepricingatncrunch.net,orthere'sasimilaropensourceprojectatcontinuoustests.com.

Onewayofenforcingtestingistousegatedcheck-insinTFS,butthiscanbealittledraconian,andifyouuseanSCM,suchasGit,thenit'seasiertoworkonbranchesandsimplyblockmergesuntilallthetestspass.Youwanttoencouragedeveloperstocheck-inearlyandoftenbecausethismakesmergeseasier.Therefore,it'sabadideatohavefeaturesinprogresssittingonworkstationsforalongtime(generallynolongerthanaday).

Page 287: ASP.NET Core 1.0 High Performance

ContinuousintegrationCIsystemsautomaticallybuildandtestallofyourbranchesandfeedthisinformationbacktoyourversioncontrolsystem.Forexample,usingtheGitHubAPI,youcanblockthemergingofpullrequestsuntilthebuildserverreportsasuccessfullytestedmergeresult.

BothBitbucketandGitLabofferfreeCIsystems,calledpipelines,soyoumaynotneedanyextrasystemsinadditiontooneforsourcecontrolbecauseeverythingisinoneplace.GitLabalsooffersanintegratedDockercontainerregistry,andthereisanopensourceversionthatyoucaninstalllocally..NETCoreandVisualStudiosupportDockerwell,andwe'llcoverthisagainlaterinthechapter.

YoucandosomethingsimilarwithVisualStudioTeamServicesforCIbuildsandunittesting.VisualStudioalsohasGitservicesbuiltintoit.

Thisprocessworkswellforunittestingbecauseunittestsmustbequicksothatyougetfeedbackearly.Shorteningtheiterationcycleisagoodwayofincreasingproductivity,andyou'llwantthelagtobeassmallaspossible.

However,runningtestsoneachbuildisn'tsuitableforalltypesoftestingbecausenotalltestscanbequick.Inthiscase,you'llneedanadditionalstrategysoasnottoslowdownyourfeedbackloop.

Note

Therearemanyunittestingframeworksavailablefor.NET,forexample,NUnit,xUnit,andMSTest(Microsoft'sunittestframework)alongwithmultiplegraphicalwaysofrunningtestslocally,suchastheVisualStudioTestExplorerandtheReSharperplugin.Peoplehavetheirfavorites,butitdoesn'treallymatterwhatyouchoosebecausemostCIsystemswillsupportallofthem.

Page 288: ASP.NET Core 1.0 High Performance

SlowtestingSometestsareslow,butevenifeachtestisfast,theycaneasilyadduptoalengthytimeifyouhavealotofthem.Thisisespeciallytrueiftheycan'tbeparallelizedandneedtoberuninsequence,soyoushouldalwaysaimtohaveeachteststandonitsownwithoutanydependenciesonothers.

It'sgoodpracticetodivideyourtestsintoringsofimportancesothatyoucanatleastrunasubsetofthemostcrucialoneveryCIbuild.However,ifyouhavealargetestsuiteorsometeststhatareunavoidablyslow,thenyoumaychoosetoonlyruntheseonceaday(perhapsovernight)oreveryweek(maybeovertheweekend).

Sometestingissimplyslowbynatureandperformancetestingcanoftenfallintothiscategory,forexample,loadtestingorUserInterface(UI)testing.Weusuallyclassthisasintegrationtesting,ratherthanunittestingbecausetheyrequireyourcodetobedeployedtoanenvironmentfortestingandthetestscan'tsimplyexercisethebinaries.

Tomakeuseofsuchautomatedtesting,youwillneedtohaveanautomateddeploymentsysteminadditiontoyourCIsystem.Ifyouhaveenoughconfidenceinyourtestsystem,thenyoucanevenhavelivedeploymentshappenautomatically.Thisworkswellifyoualsousefeatureswitchingtocontroltherolloutofnewfeatures.

Wewon'tgointotheimplementationdetailsofContinuousIntegrationorautomateddeploymentsinthisbook.However,wewillcoverfeatureswitching,howtoapplyperformancetestingtoCIprocesses,andwhattodowhenyoudiscoveraregression.

Page 289: ASP.NET Core 1.0 High Performance

FixingperformanceregressionsIfyoudiscoveraperformanceissueattheunittestingstage,thenyoucansimplyreworkthisfeature,butit'smorelikelythattheseproblemswillsurfaceinalatertestingphase.Thiscanmakeitmorechallengingtoremedytheproblembecausetheworkmayalreadyhavebeenbuiltuponandhaveothercommitsontopofit.

Thecorrectcourseofactionisoftentoback-outregressionsimmediatelyoratleastassoonaspossibleupondiscovery.Delayswillonlymaketheissuehardertofixlater,whichiswhyit'simportanttogetfastfeedbackandhighlightproblemsquickly.

It'simportanttobedisciplinedandalwaysremoveregressions,eventhoughitmaybepainful.Ifyoulettheoccasionalminorregressionin,thenyoucaneasilybecomesloppyandletmoreseriousonesinovertimebecauseoftheprecedentitsets.

Page 290: ASP.NET Core 1.0 High Performance

LoadtestingLoadtestingistheprocessofdiscoveringhowmanyconcurrentusersyourwebappcansupport.Yougenerallyperformitonatestenvironmentwithatoolthatgraduallyrampsupasimulatedload,forexample,JMeter(jmeter.apache.org).Perhaps,you'dpreferusingaJMetercompatiblecloudservice,suchasBlazeMeter,oranalternative,suchasLoader.io,ifyourtestsystemsareweb-facing.

Loadtestingcantakeasignificantamountoftimedependingonthescaleofyourservicebecauseitcanbeconfiguredtocontinueuntilthetestenvironmentgetsunacceptablyslowforusersorfallsoverandbecomesunresponsive.Youneedtobeextremelycarefulwithloadtestingandnotonlyfromthepointofviewofaccidentallytestingyourlivesystemstodestructionwhilethey'reinuse.

Youalsoneedtobewaryofgettingfalseresults,whichmaymisleadyouintoconcludingthatyoursystemcanhandlemoreloadthanitactuallywill.Balancingthesetwocompetingconcernsofsafetyandrealismcanbedifficult.It'simportanttogetrealisticresults,butyouneedtobalancethisagainstnotstressingyourproductionenvironmentandimpactingtheexperienceofrealusers.

Page 291: ASP.NET Core 1.0 High Performance

RealismKeepingitrealisanimportantprincipleofperformancetesting.Ifyoudon'tusearealisticenvironmentandworkload,thenyourresultsmaybeworsethanhavingnodatabecausetheycouldmisleadyouintobaddecisions.Whenyouhavenoinformation,youatleastknowthatyou'reinthedarkandjustguessing.

We'llcoverworkloadsandfeatureswitchingshortly,includinganexampleofhowtoimplementyourownsimpleversionfromscratch.First,let'slookathowtomakeyourtestenvironmentsrepresentativeofproduction.

Realisticenvironments

Usingatestenvironmentthatisasclosetoproduction(oraslive-like)aspossibleisagoodsteptowardensuringreliableresults.Youcantryanduseasmallersetofserversandthenscaleyourresultsuptogetanestimateofliveperformance.However,thisassumesthatyouhaveanintimateknowledgeofhowyourapplicationscalesandwhathardwareconstraintswillbethebottlenecks.

Abetteroptionistouseyourliveenvironmentorratherwhatwillbecomeyourproductionstack.Youfirstcreateastagingenvironmentthatisidenticaltolive,thenyoudeployyourcodetoit,andthenyourunyourfulltestsuite,includingacomprehensiveperformancetest,ensuringthatitbehavescorrectly.Onceyouarehappy,thenyousimplyswapstagingandproduction,perhapsusingDNSorAzurestagingslots.

Thefollowingdiagramshowshowyoufirstreleasetostagingandgolivesimplybymakingstagingbecomeproduction:

Page 292: ASP.NET Core 1.0 High Performance

Youroldliveenvironmentnoweitherbecomesyourtestenvironmentorifyouuseimmutable

Page 293: ASP.NET Core 1.0 High Performance

cloudinstances,thenyoucansimplyterminateitandSpin-upanewstagingsystem.Thisconceptisknownasblue-greendeployment,butunfortunatelyspecificimplementationinstructionsarebeyondthescopeofthisbook.

Youdon'tnecessarilyhavetomoveallusersacrossatonceinabigbang,andyoucanmoveafewoverfirsttotestwhethereverythingiscorrect.We'llcoverthisshortlyinthesectiononfeatureswitching.

Realisticworkloads

Anotherimportantpartofperformingrealistictestingistouserealdataandrealworkloads.Syntheticdataoftenwon'texerciseasystemfullyorfindexoticedgecases.Youcanusefuzzingtogeneraterandomdata,butifyouhaveaproductionsystem,thenyoucansimplyusethedatafromthisandparseyourlogstogeneratearealisticworkloadtoreplay.

Obviously,don'treplayactionsontoalivesystemthatcouldmodifyuserdataandbewaryofdataprivacyconcernsoranyactionthatcouldgenerateanexternalevent,forexample,sendingamasse-mailorchargingacreditcard.Youcanuseadedicatedtestsystem,butyoustillneedtobecarefultostuboutanyexternalAPIsthatdon'thaveatestversion.

Anotherapproachistousedummyusersforyourtestingifyoudon'tmindyourusersdiscoveringthefakesandpossiblyinteractingwiththem.OnecaseofthisapproachisNetflix'scultExampleShow,whichisahomemadevideoofanemployeerunningaroundtheirofficegroundswithalaptop.

Featureswitching

Analternativetofakeusersortestenvironmentsistorunperformancetestsonyourrealliveenvironmentusinggenuineusersastheyinteractwithyourwebapplication.Youcanusefeatureswitchingtograduallyrolloutanewfeaturetoasmallsubsetofyouruserbaseandmonitorthesystemforexcessiveload.Ifeverythingseemsnormal,thenyoucancontinuetherollout;otherwise,youcanrollback.

Note

Youmayhearsimilarideasreferredtobyothernames,suchasFeatureFlags,FeatureToggles,CanaryReleases,orBranchbyAbstraction.Someofthesemayhavesubtlydifferentmeaningsbutthegeneralguidingprincipleofgraduallyreleasingachangeismuchthesame.

Thefollowingdiagramshowshowyoucouldprogressivelymigrateuserstoanewfeaturebydeployingitbutnotinitiallyenablingit.Yourfirstuserscouldbemembersofstaffsothatanyissuesaredetectedearly:

Page 294: ASP.NET Core 1.0 High Performance

Onceallusersareconsumingthenewfeature,thenyoucansafelyremovetheoldfeature(andthefeatureswitchitself).It'sagoodideatoregularlytidyuplikethistoavoidclutterandmakelaterworkeasier.

Ifyoudiscoverthatyoursystemexperiencesexcessiveloadasyouslowlyincreasethepercentageofusersonthenewfeature,thenyoucanhalttherolloutandavoidyourserversbecomingoverloadedandunresponsive.Youthenhavetimetoinvestigateandeitherbackoutof

Page 295: ASP.NET Core 1.0 High Performance

thechangeorincreaseavailableresources.

Onevariationonthisthemeiswhenanewfeaturerequiresadatamigrationandthismigrationiscomputationallyornetworking-intensive,forexample,migratinguser-submittedvideostoanewhomeandtranscodingthemintheprocess.Inthiscase,theexcessiveloadthatyouaremonitoringwillonlybetransient,andyoudon'tneedtobackoutofafeature.Youonlyneedtoensurethattherateofmigrationislowenoughtonotexcessivelytaxyourinfrastructure.

Althoughthenewfeatureisusuallybranchedtoincode,youcaninsteadperformswitchingatthenetworklevelifyouuseblue-greendeployment.ThisisknownasacanaryreleaseandcanbedoneattheDNSorloadbalancerlevel.However,specificimplementationdetailsareagainbeyondtheremitofthisbook.

Youcanfindmanyopensourcefeatureswitchinglibrariesonlineoryoucouldwriteyourown,whichwewillshowyouhowtodolater.Acoupleof.NETfeature-switchinglibrariesaregithub.com/mexx/FeatureSwitcherandgithub.com/Jason-roberts/FeatureToggle.Unfortunately,neitheroftheseworkon.NETCoreyet,althoughsupportisplannedforFeatureToggle.Therearealsopaidcloudservicesavailable,whichoffereasymanagementinterfaces,suchasLaunchDarkly.

Note

Libraryandframeworksupportfor.NETCoreandASP.NETCorechangerapidly,socheckANCLAFS.comforthelatestinformation.

Toillustratefeatureswitching,let'sbuildourownextremelysimpleimplementationforanASP.NETCorewebapplication.Tostartwith,wetakethedefaultexistinghomepageview(Index.cshtml)andmakeacopy(IndexOld.cshtml).WethenmakeourchangestoIndex.cshtml,butthesearen'timportantforthepurposesofthisdemo.

InHomeController.cs,wechangethelogictoreturnthenewviewarelativelysmallpercentageofthetime,andtheoldoneotherwise.Theoriginalcodewassimplythefollowing:

publicIActionResultIndex()

{

returnView();

}

Wechangethisactiontoreturnthenewviewinaquarterofthecases,likethefollowing:

publicIActionResultIndex()

{

varrand=newRandom();

if(rand.Next(99)<25)

{

returnView();

}

returnView("IndexOld");

}

Page 296: ASP.NET Core 1.0 High Performance

Thiscodepicksarandomnumberoutofahundred,andifitislessthan25,thenitloadsthenewview.Clearly,youwouldn'thardcodevalueslikethis,andyouwouldprobablyuseadatabasetostoreconfigurationandcontrolitwithawebadminpage.

Ifyouloadthepageinabrowser,thenthreeoutoffourtimesyoushouldgettheoriginalpage,whichlookslikethefollowing:

However,roughlyoneeveryfourpageloads,youwillgetthenewpage,whichlookslikethefollowing:

Page 297: ASP.NET Core 1.0 High Performance

Weremovedthecarouselandcutthenumberofimageloadsinhalf.Youcanseethedifferenceinthebrowserdevelopertools,forexample,theFirefoxperformanceanalysisfortheoriginallookslikethefollowing:

Page 298: ASP.NET Core 1.0 High Performance

Whereasforthenewversionitlookslikethis.

Page 299: ASP.NET Core 1.0 High Performance

Youcanseethatthenumberofimagesdecreased,whichhasreducedthepagesizeandthetotalnumberofrequestsrequired.

Note

ThesemeasurementsweretakenwiththehostingenvironmentsettoProduction.IfyouremainwiththedefaultofDevelopment,thenyourresultswilldiffer.Refertothefollowingdocumentationpageforhowtochangethis:docs.asp.net/en/latest/fundamentals/environments.html.

Oncethenewviewhasbeenprogressivelyrolledouttoallusers(withnoperformanceproblems),thentheactionmethodcodecanberevertedtotheoriginalstateandtheoldviewdeleted.Obviously,thisisatrivialexample.Hopefully,youcannowseehowfeatureswitchingcanbeperformed.

Usingfeatureswitchingtorolloutinthiswayworkswellforperformancetesting,butyouneedtobeconfidentthatyournewcodeisfunctionallycorrectoratleastsafetodeploy.However,in

Page 300: ASP.NET Core 1.0 High Performance

certaincircumstancesyoucanalsotestfunctionalitybyextendingthisapproachandperformingexperiments.

Page 301: ASP.NET Core 1.0 High Performance

ExperimentingforscienceIfyoutakethefeatureswitchingrollouttoitslogicalconclusion,thenyoucanswitchonanewrefactoredversionforasmallpercentageofusers,butnotactuallyexposetheoutput.Youwillruntheexistingversioninparallelasacontrolandshowthistotheuser.However,youwillcollecttheresultsofbothversions,includingperformancedata.Youcanthencomparethemtoensurethatthenew(hopefullyhigherperformance)versioniscorrectandconsistentwiththeexistingbehavior.

GitHubhaveanopensourceRubylibrary,calledScientist,whichtheyusedtosuccessfullyrefactortheirpermissionsandmergingcode.Intheprocess,theydiscoveredexistinglegacybugs,foundmissingfeatures,optimizeddatabasequeries,andswappedasearchsystem.Scientistnotonlydisplaysthecorrectnessofnewcodebutalsoitsperformancerelativetotheoldimplementation.

Tip

AnimportantconcernwithScientist(oranymethodusingthisexperimentationapproach)istonotchangedata.Alloperationsshouldberead-onlyandhavenosideeffects;otherwise,youwillperformthemodificationmorethanonce,whichcouldhaveundesirableconsequences.

There'sa.NETportofScientistbyGitHubemployeePhilHaack,calledScientist.NET,andyoucangetitatgithub.com/Haacked/Scientist.net.YoucouldalsoinstallitviaNuGet.However,it'scurrentlyaprereleaseasit'sstillaworkinprogress,butitshouldsupport.NETCore.CheckANCLAFS.comforthelatestinformation.

ThisideaofexperimentingonusersissimilartothemarketingconceptofA/Btesting,whichisusedtodiscoverconversioneffectiveness.However,withScientist,youdon'ttypicallyshowtheusersdifferentoutputsorevenintendtheoutputtochange,youjustrecordthenewoutputforthesubsetofusersthatyouhaveitenabledfor.

Page 302: ASP.NET Core 1.0 High Performance

A/BtestingA/Btestingissimilartofeatureswitching,butweusuallyuseittotesttheeffectivenessofdifferentwebpagedesignsandhowtheyaffecttheconversionfunnelanalytics.Wenormallyuseitfordigitalmarketingratherthanforsoftwaredevelopmentbecauseit'slessaboutwhatiscorrectandmoreaboutwhatcustomersprefer.However,theunderlyingtechnicalprincipalsarecomparabletofeatureswitchingandexperimenting.

Inasimpleexample,youservehalfofyourvisitorstheoldversionofapageandtheotherhalfanewversiondesignedtoincreaseengagement.Youthenrecordhowmanyvisitorsclickthroughorperformsomeactiononeachvariant.Ifthenewversionperformsbetter,thenyoukeepitandrollitouttoeveryone.However,ifitconvertedworse,yourollbacktotheoldversionandtryagain.

Youcanseethatthisisverysimilartohowfeatureswitchingworks,andyoucanusethesametoolstodoboth.Theonlydifferenceiswhatyouaremeasuring,useranalyticsorthehealthofyourinfrastructure.

A/BtestingisnotnormallyusedforbackendfeaturesandissimplytoassessUIalternatives.However,itisdifferenttofunctionallytestingyourwebinterface,solet'scoverthebasicsofUItestingnow.

Page 303: ASP.NET Core 1.0 High Performance

UserinterfacetestingThere'soneareaofanapplicationthatistraditionallydifficulttotest,andthat'stheUI.ThisisparticularlythecaseforGUIs,asusedinwebapplications.Onereasonforthisisthatuserstypicallyhavealotofflexibilityinhowtheydisplaytheirinterface,andthisisespeciallytrueforwebbrowsers.Anaïvepixel-basedtestingapproachisgoingtobeextremelyfragile.

Youneedtodesignyourapplicationtobeeasilytestable,andtheUIisnoexception.WhileitispossibletotesttheUIofapoorly-designedlegacyapplicationandthismayevenbetheeasiesttestingapproach,ifyouconsiderUItestingupfront,thenlifewillbealoteasier.Forexample,includingsensibleIDsonyourHTMLDocumentObjectModel(DOM)elementsmakestestingmuchmorestraightforwardandlessfragile.

Checkingyourapplicationfromawebbrowserperspectivecanbeausefuladditionalstepontopofautomatedunitandintegrationtesting.Youcanuseitnotonlytotestforfunctionalcorrectnessandregressionsbutalsotomeasureclientsideperformance,whichisincreasinglyimportant.TherearemanyUItestingtoolsavailable,mostofwhichyoucanintegrateintoyourCIpipelinetoautomatetesting.

WebUItestingtools

Oneofthemostpopularweb-testingtoolsisSelenium,whichallowsyoutoeasilywritetestsandautomatewebbrowsersusingWebDriver.Seleniumisusefulformanyothertasksapartfromtesting,andyoucanreadmoreaboutitatdocs.seleniumhq.org.

Note

WebDriverisaprotocoltoremotecontrolwebbrowsers,andyoucanreadaboutitatw3c.github.io/webdriver/webdriver-spec.html.

Seleniumusesrealbrowsers,thesameversionsyouruserswillaccessyourwebapplicationwith.Thismakesitexcellenttogetrepresentativeresults,butitcancauseissuesifitrunsfromthecommandlineinanunattendedfashion.Forexample,youmayfindyourtestserver'smemoryfullofdeadbrowserprocesseswhichtimedout.

Youmayfinditeasiertouseadedicatedheadlesstestbrowser,which,whilenotexactlythesameaswhatyouruserswillsee,ismoresuitableforautomation.Ofcourse,thebestapproachistouseacombinationofboth,perhapsrunningheadlesstestsfirstandthenrunningthesametestsonrealbrowserswithWebDriver.

Oneofthemostwell-knownheadlesstestbrowsersisPhantomJS.ThisisbasedontheWebKitengine,soitshouldgiveyousimilarresultstoChromeandSafari.PhantomJSisusefulformanythingsapartfromtesting,suchascapturingscreenshots,andyoucandriveitwithmanydifferenttestingframeworks.Asthenamesuggests,youcancontrolPhantomJSwithJavaScript,andyoucanreadmoreaboutitatphantomjs.org.

Page 304: ASP.NET Core 1.0 High Performance

Note

WebKitisanopensourceengineforwebbrowsers,whichwasoriginallypartoftheKDELinuxdesktopenvironment.ItismainlyusedinApple'sSafaribrowser,butaforkcalledBlinkisusedinGoogleChrome,Chromium,andOpera.Youcanreadmoreatwebkit.org.

Otherautomatabletestingbrowsers,basedondifferentengines,areavailable,buttheyhavesomelimitations.Forexample,SlimerJS(slimerjs.org)isbasedontheGeckoengineusedbyFirefox,butisnotfullyheadless.

Youprobablywanttouseahigher-leveltestingutilityratherthanscriptingbrowserenginesdirectly.OnesuchutilitythatprovidesmanyusefulabstractionsisCasperJS(casperjs.org),whichsupportsrunningonbothPhantomJSandSlimerJS.

AnothertoolisCapybara,whichallowsyoutoeasilysimulateuserinteractionsinRuby.ItsupportsSelenium,WebKit,Rack,andPhantomJS(viaPoltergeist),althoughit'smoresuitableforRailsapps.Youcanreadmoreatjnicklas.github.io/capybara.

ThereisalsoTrifleJS(triflejs.org),whichusesthe.NETWebBrowserclass(theInternetExplorerTridentengine),butthisisaworkinprogress.Additionally,there'sWatir(watir.com),whichisasetofRubylibrariestargetingInternetExplorerandWebDriver.However,neitherhavebeenupdatedinawhile,andIEhaschangedalotrecently.

Note

MicrosoftEdge(codenamedSpartan)isthenewversionofIE,andtheTridentenginewasforkedtoEdgeHTML.TheJavaScriptengine(Chakra)wasopensourcedasChakraCore(github.com/Microsoft/ChakraCore).

Itshouldn'tmattertoomuchwhatbrowserengineyouuse,andPhantomJSwillworkfineasafirstpassforautomatedtests.Youcanalwaystestwithrealbrowsersafterusingaheadlessone,perhapswithSeleniumorwithPhantomJSusingWebDriver.

Tip

Whenwerefertobrowserengines(WebKit/Blink,Gecko,orTrident/EdgeHTML),wegenerallymeanonlytherenderingandlayoutengine,nottheJavaScriptengine(SFX/Nitro/FTL/B3,V8,SpiderMonkey,orChakra/ChakraCore).

You'llprobablystillwanttouseautilitysuchasCasperJStomakewritingtestseasier,andyou'lllikelyneedatestframework,suchasJasmine(jasmine.github.io)orQUnit(qunitjs.com)too.YoucanalsouseatestrunnerthatsupportsbothJasmineandQUnit,suchasChutzpah(mmanela.github.io/chutzpah).

YoucanintegrateyourautomatedtestswithmanydifferentCIsystems,forexample,JenkinsorJetBrainsTeamCity.Ifyoupreferacloud-hostedoption,thenthere'sTravisCI(travis-ci.org)and

Page 305: ASP.NET Core 1.0 High Performance

AppVeyor(appveyor.com),whichisalsosuitabletobuild.NETapps.

YoumayprefertorunyourintegrationandUItestsfromyourdeploymentsystem,forexample,toverifyasuccessfuldeploymentinOctopusDeploy.Therearealsodedicated,cloud-basedweb-applicationUItestingservicesavailable,suchasBrowserStack(browserstack.com).

AutomatingUIperformancetests

AutomatedUItestsareclearlygreattocheckforfunctionalregressions,buttheyarealsousefultotestperformance.Youhaveprogrammaticaccesstothesameinformationprovidedbythenetworkinspectorinthebrowserdevelopertools.

YoucanintegratetheYSlow(yslow.org)performanceanalyzerwithPhantomJS,enablingyourCIsystemtocheckforcommonweb-performancemistakesoneverycommit.YSlowcameoutofYahoo!,anditprovidesrulesusedtoidentifybadpractices,whichcanslowdownwebapplicationsforusers.It'sasimilarideatoGoogle'sPageSpeedInsightsservice(whichyoucanautomateviaitsAPI).

However,YSlowisprettyold,andthingshavemovedoninwebdevelopmentrecently,forexample,HTTP/2.Amodernalternativeis"thecoach"fromsitespeed.io,andyoucanreadmoreatgithub.com/sitespeedio/coach.Youshouldcheckouttheirotheropensourcetoolstoo,suchasthedashboardatdashboard.sitespeed.io,whichusesGraphiteandGrafana.

Youcanalsoexportthenetworkresults(inindustrystandardHARformat)andanalyzethemhoweveryoulike,forexample,visualizingthemgraphicallyinwaterfallformat,asyoumightdomanuallywithyourbrowserdevelopertools.

Note

TheHTTPArchive(HAR)formatisastandardwayofrepresentingthecontentofmonitorednetworkdatatoexportittoothersoftware.YoucancopyorsaveasHARinsomebrowserdevelopertoolsbyright-clickinganetworkrequest.

Page 306: ASP.NET Core 1.0 High Performance

StayingalertWheneveryouperformtesting,particularlyUIorperformancetesting,youwillgetnoisyresults.Reliabilityisnotperfect,andtherewillalwaysbefailuresthatarenotduetobugsinthecode.Youshouldn'tletthesefalsepositivescauseyoutoignorefailingtests,andalthoughtheeasiestcourseofactionmaybedisablingthem,thecorrectthingtodotomakethemmorereliable.

Tip

Thescientificallymindedknowthatthereisnosuchthingasaperfectfilterinbinaryclassification,andalwayslookattheprecisionandrecallofasystem.Knowingtherateoffalsepositivesandnegativesisimportanttogetagoodideaoftheaccuracyandtradeoffsinvolved.

Toavoidtestingfatigue,itcanbehelpfultoengagedevelopersandinstillaresponsibilitytofixfailingtests.Youdon'twanteveryonethinkingthatit'ssomebodyelse'sproblem.Itshouldbeprettyeasytoseewhobrokeatestbythecommitinversioncontrol,andit'sthentheirjobtofixthebrokentest.

Youcanhaveabitoffunwiththisandcreatesomethingabitmoreinterestingthanawallmounteddashboard.Althoughhavinginformationradiatorsisusefulifyoudon'tgetdesensitizedtothem.There'splentyofcheapInternetofThings(IoT)hardwareavailabletoday,whichallowsyoutoturnsomeinterestingthingsintobuildortestfailurealarms.Forexample,anArduino-controlledtrafficlight,anESP8266-operatedfoam-missileturret,oraRaspberryPi-poweredanimatronicfigure.

Page 307: ASP.NET Core 1.0 High Performance

DevOpsWhenusingautomationandtechniquessuchasfeatureswitching,itisessentialtohaveagoodviewofyourenvironmentssothatyouknowtheutilizationofallthehardware.Goodtoolingisimportanttoperformthismonitoring,andyouwanttoeasilybeabletoseethevitalstatisticsofeveryserver.ThiswillconsistofatleasttheCPU,memory,anddiskspaceconsumption,butitmayincludemore,andyouwillwantalarmssetuptoalertyouifanyofthesestrayoutsideallowedbands.

ThepracticeofDevOpsistheculminationofalloftheautomationwecoveredpreviouslywithdevelopment,operations,andquality-assurancetestingteamsallcollaborating.Theonlymissingpiecesleftnowaretoprovisionandconfigureinfrastructureandthenmonitoritwhileinuse.AlthoughDevOpsisaculture,thereisplentyoftoolingthatcanhelp.

Page 308: ASP.NET Core 1.0 High Performance

DevOpstoolingOneoftheprimarythemesofDevOpstoolingisdefininginfrastructureascode.Theideaisthatyoushouldn'tmanuallyperformatask,suchassettingupaserver,whenyoucancreatesoftwaretodoitforyou.Youcanthenreusetheseprovisioningscripts,whichwillnotonlysaveyoutimebutwillalsoensurethatallofthemachinesareconsistentandfreeofmistakesormissedsteps.

Provisioning

Therearemanysystemsavailabletocommissionandconfigurenewmachines.Somepopularconfiguration-managementautomationtoolsareAnsible(ansible.com),Chef(chef.io),andPuppet(puppet.com).

NotallofthesetoolsworkgreatonWindowsservers,partlybecauseLinuxiseasiertoautomate.However,youcanrunASP.NETCoreonLinuxandstilldeveloponWindows,usingVisualStudiowhiletestinginaVM.DevelopingforaVMisagreatideabecauseitsolvestheproblemsinsettingupenvironmentsandissueswhereit"worksonmymachine"butnotinproduction.

Vagrant(vagrantup.com)isagreatcommandlinetooltomanagedeveloperVMs.Itallowsyoutoeasilycreate,Spin-up,andsharedeveloperenvironments.ThesuccessortoVagrant,Otto(ottoproject.io)takesthisastepfurtherandabstractsdeploymenttoosothatyoucanpushtomultiplecloudproviderswithoutworryingabouttheintricaciesofCloudFormation,OpsWorks,oranythingelse.

Ifyoucreateyourinfrastructureascode,thenyourscriptscanbeversionedandtested,justlikeyourapplicationcode.We'llstopbeforewegettoofarofftopic,butthepointisthatifyouhavereliableenvironments,whichyoucaneasilyverify,instantiate,andperformtestingon,thenCIisaloteasier.

Monitoring

Monitoringisessential,especiallyforwebapplications,andtherearemanytoolsavailabletohelpwithit.Apopularopensourceinfrastructure-monitoringsystemisNagios(nagios.org).AnothermoremodernopensourcealertingandmetricstoolisPrometheus(prometheus.io).

Ifyouuseacloudplatform,thentherewillbemonitoringbuiltin,forexample,AWSCloudWatchorAzureDiagnostics.Therearealsocloudservicestodirectlymonitoryourwebsite,suchasPingdom(pingdom.com),UptimeRobot(uptimerobot.com),Datadog(datadoghq.com),andPagerDuty(pagerduty.com).

Youprobablyalreadyhaveasysteminplacetomeasureavailability,butyoucanalsousethesamesystemstomonitorperformance.Thisisnotonlyhelpfultoensurearesponsiveuserexperience,butitcanalsoprovideearlywarningsignsthatafailureisimminent.Ifyouareproactiveandtakepreventativeaction,thenyoucansaveyourselfalotoftroublereactivelyfightingfires.

Page 309: ASP.NET Core 1.0 High Performance

Thisisn'tabookonoperations,butithelpstoconsiderapplicationsupportrequirementsatdesigntime.Development,testing,andoperationsaren'tcompetingdisciplines,andyouwillsucceedmoreoftenifyouworkasoneteamratherthansimplythrowinganapplicationoverthefenceandsayingit"workedintest,opsproblemnow."

Page 310: ASP.NET Core 1.0 High Performance

HostingIt'swellworthconsideringtheimplicationsofvarioushostingoptionsbecauseifdeveloperscan'teasilyaccesstheenvironmentstheyneed,thenthiswillreducetheiragility.Theymayhavetoworkaroundanavailabilityproblemandendupusinginsufficientorunsuitablehardware,whichwillhamperprogressandcausefuturemaintenanceproblems.Ortheirworkwillsimplybeblockedanddeliverysetback.

Unlessyouareaverylargeorganization,hostingin-houseisgenerallyabadideaforreliability,flexibility,andcostreasons.Unlessyouhavesomeverysensitivedata,thenyoushouldprobablyuseadatacenter.

Youcanco-locateserversinadatacenter,butthenyouneedstafftobeoncalltofixhardwareproblems.Oryoucanrentaphysicalserverandrunyourapplicationon"baremetal",butyoumaystillneedremotehandstoperformresetsorothertasksonthemachine.

Themostflexiblesituationistorentself-servicevirtualmachines,commonlyknownascloudhosting.Therearemanyhostingcompaniesthatofferthis,butthebigplayersareAmazon,Google,andMicrosoft.

Microsoft'sAzureistheobviouschoicefora.NETshopandithasimprovedimmenselysincelaunchcomparedtoitsoriginaloffering.ItsPlatformasaService(PaaS)tohost.NETapplicationsisthemostpolishedandtheeasiesttogetrunningonquickly.ItalsoofferslotsofextraservicesthatgobeyondsimpleVMs.

However,.NETCoreandASP.NETCorearenewtypesofframework,whicharenotaimedsolelyatC#developers,whowouldusuallypickthedefaultoptionofferedbyMicrosoft.Thetargetedmarketisdeveloperswhomaybeusedtochoosingalternativeplatformsandopensourceframeworks.Therefore,itmakessensetocoverotheroptions,whichpeoplenewto.NETmaybemorefamiliarwith.

Note

ThedifferencebetweenPaaSandInfrastructureasaService(IaaS)isthatPaaSishigherlevelandprovidesaservicetorunapplications,notcomputers.IaaSsimplyprovidesyouwithaVM.However,withPaaS,thisisabstractedaway,andyoudon'tneedtoworryaboutsettingupandupdatinganinstance.

AmazonWebServices(AWS)isthemostestablishedcloudhost,anditstartedbyonlyofferingIaaS,althoughtheynowofferPaaSoptions.Forexample,ElasticBeanstalksupports.NET.EventhoughWindows(andSQLServer)supporthasimproved,itisstillnotfirstclass,andLinuxisclearlytheirmainplatform.

However,nowthat.NETCoreandSQLServer2016runonLinux,thismaybelessofaproblem.YouwillpayapremiumforWindowsserverinstances,butyou'realsochargedmoreforsome

Page 311: ASP.NET Core 1.0 High Performance

enterpriseLinuxdistributions(RedhatandSUSE).However,youcanrunotherLinuxdistributions,suchasUbuntuorCentOSwithoutpayingapremium.

GoogleCloudPlatformusedtoconsistofAppEngine(GAE),whichwasquitearestrictivePaaS,butitisgettingmoreflexible.TheynowofferagenericIaaScalledComputeEngine(GCE),andthere'sanewflexibleversionofGAE,whichismorelikeGCE.Thesenewofferingsareuseful,asyoucouldn'ttraditionallyrun.NETonGAE,andtheyalsoprovideotherproductssuchaspre-emptibleVMsandacloudCDN(withHTTPSatnoextracost).

Azuremaystillbethebestchoiceforyou,anditintegrateswellwithotherMicrosoftproducts,suchasVisualStudio.However,itisworthhavinghealthycompetitionbecausethiskeepseveryoneinnovating.It'sdefinitelyagoodideatofrequentlylookatthepricingofalloptions,(whichchangesregularly)becauseyoucansavealotofmoneydependingontheworkloadthatyourun.Youcanavoidvendorlock-inbyavoidingcustomservices.

Tip

IfyouareeligibleforMicrosoft'sBizSparkprogram,thenyoucangetthreeyearsofAzurecredits(suitabletohostasmallapplication).YoualsogetanMSDNsubscriptionforfreesoftwarelicenses.

Whateverhostingprovideryouchoosetouse,itissensibletoavoidvendorlock-inanduseservicesthataregeneric,whichyoucaneasilyswapforanalternative.Forexample,usinghostedopensourcesoftware,suchasPostgreSQL,Redis,orRabbitMQ,ratherthananequivalentcustomcloudproviderproduct.Youcanalsotakearesilientmulticloudapproachtoprotectyourselffromanoutageofasingleprovider.

Dockerisagreattechnologyforthispurposebecausemanydifferentcloudservicessupportit.Forexample,youcanrunthesamecontaineronAzureContainerService,DockerCloud,AWSEC2ContainerService,andGoogle'sKubernetesContainerEngine.

DockeralsorunsonWindows(usingHyper-V),andinthenewversionofVisualStudioyoucandeploytoanddebugintoacontainer.ThiscanrunASP.NETCoreonLinux,andwhenyouarereadytodeploy,youcanjustpushtoproductionandhaveconfidencethatitwillworkasitdidonyourmachine.Youcanreadmoreaboutthisatdocker.com/Microsoft,andtherearesomeinterestingvideosontheDockerblog.

Note

Whenchoosingacloud(orevenaregion),it'simportanttonotonlyconsiderthemonetarycost.Youshouldalsofactorinenvironmentalconcerns,suchasthemainfuelusedforthepowersupply.Forexample,someregionscanbecheaper,butthismaybebecausetheyusedirtycoalpower,whichcontributestoclimatechangeandourfuturesecurity.

Page 312: ASP.NET Core 1.0 High Performance

SummaryInthischapter,yousawhowyoumightintegrateautomatedtestingintoaCIsysteminordertomonitorforperformanceregressions.Youalsolearnedsomestrategiestorolloutchangesandensurethattestsaccuratelyreflectreallife.WealsobrieflycoveredsomeoptionsforDevOpspracticesandcloud-hostingproviders,whichtogethermakecontinuousperformancetestingmucheasier.

Inthenextchapter,we'llwrap-upeverythingthatwecoveredthroughoutthisbookandsuggestsomeareasforfurtherinvestigation.We'llreinforceourlearningssofar,giveyousomeinterestingideastothinkabout,contemplatepossiblefuturesfor.NET,andconsidertheexcitingdirectiontheplatformistaking.

Page 313: ASP.NET Core 1.0 High Performance

Chapter10.TheWayAheadThischaptersumsupwhatyoulearnedbyreadingthisbook.Itrefreshesthemaintenetsofperformanceanditremindsyouthatyoushouldalwaysremainpragmatic.We'llrecapwhyyoushouldn'toptimizejustforoptimization'ssakeandwhyyoushouldalwaysmeasuretheproblemsandresults.Thischapteralsointroducesmoreadvancedandexotictechniquesthatyoumaywishtoconsiderlearningaboutifyouneedmorespeedorareaseriousperformanceenthusiast.

Topicscoveredinthischapterincludethefollowing:

Asummaryofpreviously-coveredtopicsPlatforminvokeandnativecodeAlternativearchitectures,suchasARMAdvancedhardware(GPUs,FPGAs,ASICs,SSDs,andRAMSANs)MachinelearningandAIBigdataandMapReduceTheOrleansvirtualactormodelCustomtransportlayersAdvancedhashingfunctionsLibraryandframeworksupportThefutureof.NETCore

We'llreinforcehowtoassessandsolveperformanceissuesbyrefreshingyourmemoryofthelessonsinthepreviouschapters.You'llalsogainanawarenessofotheradvancedtechnologythat'savailabletoassistyouwithdeliveringhighperformance,whichyoumaywishtoinvestigatefurther.Finally,we'llhighlightwhatlibrariesandframeworkssupport.NETCoreandASP.NETCore,andtrytohypothesizepossiblefuturedirectionsfortheseexcitingnewplatforms.

Page 314: ASP.NET Core 1.0 High Performance

ReviewingwhatwelearnedLet'sbrieflyrecapwhatwecoveredearlierinthisbooktoserveasanaide-mémoire.

InChapter1,WhyPerformanceIsaFeature,wediscussedthebasicpremiseofthisbookandshowedyouwhyyouneedtocareabouttheperformanceofyoursoftware.Then,inChapter2,MeasuringPerformanceBottlenecks,weshowedyouthattheonlywayyoucansolveperformanceproblemsistocarefullymeasureyourapplication.

InChapter3,FixingCommonPerformanceProblems,welookedatsomeofthemostfrequentperformancemistakesandhowtofixthem.Afterthis,wewentalittledeeperinChapter4,AddressingNetworkPerformance,anddugintothenetworkinglayerthatunderpinsallwebapplications.TheninChapter5,OptimizingI/OPerformance,wefocusedoninput/outputandhowthiscannegativelyaffectperformance.

InChapter6,UnderstandingCodeExecutionandAsynchronousOperations,wejumpedintotheintricaciesofC#codeandlookedathowitsexecutioncanalterperformance.TheninChapter7,LearningCachingandMessageQueuing,weinitiallylookedatcaching,whichiswidelyregardedtobequitehard.Then,weinvestigatedmessagequeuingasawaytobuildadistributedandreliablesystem.

InChapter8,TheDownsidesofPerformanceEnhancingTools,weconcentratedonthenegativesofthetechniquesthatwepreviouslycovered,asnothingcomesforfree.TheninChapter9,MonitoringPerformanceRegressions,welookedatmeasuringperformanceagainbut,inthiscase,fromanautomationandContinuousIntegration(CI)perspective.

Page 315: ASP.NET Core 1.0 High Performance

FurtherreadingIfyou'vereadthisfar,thenyouwillprobablywantsomepointersforotherthingstoresearchandreadupon.Fortherestofthischapter,we'llhighlightsomeinterestingtopicsthatyoumaywanttolookintofurther,butwecouldn'tcoverinmoredetailinthisbook.

Page 316: ASP.NET Core 1.0 High Performance

GoingnativeOneoftheproblemswiththeoldASP.NETisthatitwasreallyslow,whichiswhyoneofthemainguidingprinciplesofASP.NETCorehasbeenperformance.Impressiveprogresshasalreadybeenmade,butthereareplentymoreopportunitiesforfurtherenhancements.

Oneofthemostpromisingareasisthenativetoolchain,whichwebrieflymentionedinChapter6,UnderstandingCodeExecutionandAsynchronousOperations.It'sstillinitsearlydaysbutitlookslikeitcouldbeverysignificant.

Previously,ifyouwantedtocallunmanagednativecodefrommanaged.NETcode,youneededtousePlatformInvoke(PInvoke),butthishadperformanceoverheadsandsafetyconcerns.Evenifyournativecodewasfaster,theoverheadsoftenmeantitwasnotworthbotheringabout.

Thenativetoolchainshouldgivenativelevelsofperformance,butwiththesafetyandconvenienceofamanagedruntime.Ahead-of-timecompilationisfascinatingandverytechnical,butitcanofferaperformanceboostalongwithsimplifieddeploymentsifweknowthearchitecture.

It'salsopossibletooptimizefordifferentprocessorsthatmayofferspecialperformancefeaturesandinstructions.Forexample,targetinglow-energyARMchipsinsteadoftheusualIntelstyleprocessors.

Page 317: ASP.NET Core 1.0 High Performance

ProcessorarchitectureTypically,whenwritingdesktoporserversoftware,youwilltargetanIntel-basedarchitecture,suchasx86orx64.However,ARM-basedchipsaregainingpopularity,andtheycanofferfantasticpowerefficiency.Ifsoftwareisspeciallyoptimizedforthem,thentheycanalsoofferexcellentperformance.

Forexample,theScratchgraphicalprogramminglanguage,usedtoteachcomputing,hasbeenoptimizedforaRaspberryPi3anditnowrunsroughlytwiceasquickasitdoesonanIntelCorei5.OthersoftwarehasalsobeenoptimizedfortheARMprocessor,forexample,theKodiopensourcemediaplayer.

ARMHoldingsissimplyanintellectualpropertycompanyandtheydon'tmakeanyprocessorsthemselves.Othercompanies,suchasAppleandBroadcom,licensethedesignsorarchitectureandfabricatetheirSystemonaChip(SoC)products.

Thismeansthattherearemanydifferentchipsavailable,whichrunmultipledifferentversionsoftheARMarchitectureandinstructionset.Thisfragmentationcanmakeithardertosupportunlessyoupickaspecificplatform.

Windows10IoTCorerunsontheRaspberryPi(version2and3)anditcannowbesetupusingthestandardNewOutOftheBoxSoftware(NOOBS)installer.Windows10IoTCoreisnotafulldesktopenvironmenttorunnormalapplications,butitdoesallowyoutomakehardwareprojectsandprogramthemwithC#and.NET.However,forwebapplications,youwouldprobablyrun.NETCoreonLinux,suchasRaspbian(basedonDebian).

Page 318: ASP.NET Core 1.0 High Performance

HardwareishardWepreviouslymentionedadditionalhardwarethatcanbeusedforcomputationinChapter6,UnderstandingCodeExecutionandAsynchronousOperations,includingGraphicsProcessingUnits(GPUs),FieldProgrammableGateArrays(FPGAs),andApplicationSpecificIntegratedCircuits(ASICs).

Notonlycanthesedevicesbeusedforspecificprocessingtasks,buttheirstoragecanbeusedaswell.Forexample,youcanborrowtheRAMfromaGPUifmainmemoryisexhausted.However,thistechniqueisnotrequiredasmuchasitusedtobewhenmemorywasmorelimited.

YoumayhaveheardofRAMSANs,whichwereSANsusingstandardRAMforpermanentstorage(withabatterybackup).However,thesehavebecomelessrelevantasSSDs(basedonflashmemory)improvedinspeedandincreasedincapacitytothepointofreplacingmechanicaldrivesformanycommontasks.

YoucanstillpurchasehighperformanceSANs,buttheywillprobablybebasedonflashmemoryratherthanRAM.IfyouuseRAMasyourmainstorage(forexample,withRedis),thenitisimportanttouseerror-correctingcodememory(ECC).ECCRAMismoreexpensive,butitisbettersuitedforserveruse.However,somecloudinstancesdon'tuseitorit'shardtofindoutwhetherit'sevenofferedbecauseitisn'tlistedinthespecification.

OneapplicationofcustomcomputationhardwareisMachineLearning(ML),specificallythedeeplearningbranchofML,usingmultilevelneuralnetworks.Thistechnologysawimpressiveadvancesinrecentyearsandthisledtoproducts,suchasself-drivingvehicles.MLapplicationscanmakeverygooduseofnon-CPUprocessing,particularlyGPUs,andNVIDIAprovidesmanytoolsandlibrariestohelpwiththis.

GooglealsorecentlyannouncedthattheybuiltacustomASIC,calledaTensorProcessingUnit(TPU),toacceleratetheirTensorFlowmachinelearninglibraryandcloudservices.Youcanreadmoreattensorflow.organdcloud.google.com/ml.

Page 319: ASP.NET Core 1.0 High Performance

MachinelearningYoudon'tonlyhavetouseArtificialIntelligence(AI)toreplacedriversandotherjobs,suchascallcenterstafforevendoctors.YoucanusesomebasicMLinyourownwebapplicationstoprovideproductsuggestionsrelevanttoyourcustomersoranalyzemarketingeffectiveness,justlikeAmazonorNetflixdo.

Youdon'tevenneedtobuildyourownMLsystems,asyoucanusecloudservices,suchasAzureML.ThisallowsyoutouseagraphicaldraganddropinterfacetobuildyourMLsystems,althoughyoucanalsousePythonandR.

Youstillneedtoknowalittlebitaboutdatascience,suchastheelementaryprinciplesofbinaryclassificationandtrainingdata,butevenso,itsignificantlyreducesthebarriertoentry.Yet,ifyouwanttofullyexploreMLandbigdatapossibilities,thenyouprobablyneedadedicateddatascientist.

YoucantryoutAzureMLatstudio.azureml.netandyoudon'tevenneedtoregister.Thefollowingscreenshotshowsanexampleofwhatitlookslike:

Page 320: ASP.NET Core 1.0 High Performance
Page 321: ASP.NET Core 1.0 High Performance

BigdataandMapReduceBigdataisprobablyanoverusedtermthesedaysandwhatissometimesdescribedasbigisusuallymorelikemediumdata.Bigdataiswhenyouhavesomuchinformationthatitisdifficulttoprocess,orevenstore,onasinglemachine.Traditionalapproachesoftenbreakdownwithbigdata,astheyarenotadequateforthehugeautomatically-acquireddatasetsthatarecommontoday.Forexample,theamountofdataconstantlycollectedbyIoTsensorsorbyourinteractionswithonlineservicescanbevast.

OnecaveatofbigdataandMListhat,althoughtheyaregoodatfindingcorrelationsinlargesetsofdatapoints,youcannotusethemtofindcausations.Youalsoneedtobemindfulofdataprivacyconcernsandbeverycarefulofnotjudgingsomeonebeforetheyhaveacted,basedonlyonapredictedpredisposition.

Note

Anonymizingdataisincrediblydifficultandisnotnearlyassimpleasremovingpersonalcontactdetails.Therehavebeenmanycasesoflarge"anonymized"datasetsbeingreleasedwhereindividualswerelatereasilyidentifiedfromtherecords.

OnetechnologythatisusefultoanalyzebigdataisMapReduce,whichisawayofsimplifyinganoperationsothatitissuitabletoruninparallelonadistributedinfrastructure.ApopularimplementationofMapReduceisApacheHadoopandyoucanusethisinAzurewithHDInsight,whichalsosupportsrelatedtools,includingApacheSparkandApacheStorm.OtheroptionstohandlelargedatasetsincludeGoogle'sCloudBigtableorBigQuery.

YoucanseetheavailableoptionsforAzureHDInsightintheportal,asshowninthefollowingimage.Somefeaturesarestillinprevieworhaverestrictions,buttheymayhavemovedtogeneralavailabilitybythetimeyoureadthis.

Page 322: ASP.NET Core 1.0 High Performance

YoucanseefromthisimagethatSparkisinpreviewandiscurrentlyavailableonlyonLinux.HadoopismoreestablishedandisalsoavailableonWindows,asshowninthefollowingscreenshot:

Page 323: ASP.NET Core 1.0 High Performance

ThenextimageshowsthatStormisalsoavailablebutnotonthepremiumpreview(includingMicrosoftRServer):

Page 324: ASP.NET Core 1.0 High Performance
Page 325: ASP.NET Core 1.0 High Performance

OrleansAnotherinterestingprojectisanopensourceframeworkfromMicrosoftcalledOrleans,whichisadistributedvirtualactormodelthatwasusedtopowerthecloudservicesofHaloXboxgames.Whatthismeansisthat,ifyoubuildyoursystembyseparatingyourlogicintoseparateactors,thisallowsittoeasilyscale,basedondemand.

InOrleans,actorsareknownasgrainsandyoucanwritetheminC#byinheritingfromaninterface.ThesearethenexecutedbyanOrleansserver,calledasilo.Grainscanbepersistedtostorage,suchasSQLorAzureTables,tosavetheirstateandtoreactivatelater.OrleanscanalsomakeuseoftheBondserializerforgreaterefficiency.

Unfortunately,Orleansdoesnotcurrentlysupport.NETCore,buttheportingworkisinprogress.Orleansallowsyoutowritesimpleandscalablesystemswithlowlatencyandyoucanreadmoreatdotnet.github.io/orleans.

Page 326: ASP.NET Core 1.0 High Performance

CustomtransportsInChapter4,AddressingNetworkPerformance,westartedwithanintroductiontoTCP/IPandbrieflymentionedUDP.WealsocoveredTLSencryptionandhowtominimizetheimpactofsecureconnectionswhilestillreapingperformancebenefits.

UDPissimplerandquickerthanTCP,butyoueitherneedtonotcareaboutreliabledelivery(multiplayergamesandvoice/videochat)orbuildyourownlayertoprovidethis.InChapter8,TheDownsidesofPerformance-EnhancingTools,wehighlightedStatsD,whichusesUDPtoavoidblockinglatencywhileloggingtoaremotecentralserver.

TherearealternativestoTLSifyouaren'tconstrainedtoabrowser,butifyou'redevelopingawebapplication,thiswillprobablyonlyapplyinsideofyourserverinfrastructure.Forexample,theWhatsAppmessagingappusesNoisePipesandCurve25519fromtheNoiseProtocolFramework(noiseprotocol.org)betweenthesmartphoneappandtheirserversinadditiontotheSignalProtocolforend-to-endencryption.

UsingNoisePipesinsteadofTLSincreasesperformancebecausefewerroundtripsarerequiredtosetupaconnection.Anotheroptionwithsimilarbenefitsisthesecurepipedaemon(spiped),asusedbyandcreatedforthesecureLinuxbackupsoftware,Tarsnap.However,youdoneedtopresharethekeys,butyoucanreadmoreaboutthisatwww.tarsnap.com/spiped.html.

Page 327: ASP.NET Core 1.0 High Performance

AdvancedhashingWecoveredhashingfunctionsafairamountinthisbook,especiallyinChapter6,UnderstandingCodeExecutionandAsynchronousOperations.Thisareaisconstantlyadvancinganditisusefultokeepaneyeonthefuturetoseewhat'scoming.AlthoughtodayitisreasonabletouseamemberoftheSHA-2familyforquickhashingandPBKDF2forslow(password)hashing,thisisunlikelytoalwaysbethecase.

Forfasthashing,thereisanewfamilyofalgorithmscalledSHA-3,whichshouldnotbeconfusedwithSHA-384orSHA-512(whicharebothintheSHA-2family).SHA-3isbasedonanalgorithmcalledKeccak,whichwasthewinnerofacompetitiontofindasuitablealgorithmforthenewstandard.OtherfinalistsincludedSkein(skein-hash.info)andBLAKE2(blake2.net),whichisfasterthanMD5,butactuallysecure.

AnalgorithmcalledArgon2wonasimilarcompetitionforpasswordhashing(password-hashing.net).Toseewhythismatters,youcanvisithaveibeenpwned.com(runby.NETsecurityguruTroyHunt)toseewhetheryourdetailsareinoneofthelargenumberofdatabreaches.Forexample,LinkedInwasbreachedanddidn'tusesecurepasswordhashing(onlyanunsaltedSHA-1hash).Consequently,mostoftheplaintextpasswordswerecracked.Therefore,ifaLinkedInaccountpasswordwasreusedonothersites,thentheseaccountscanbetakenover.

It'saverygoodideatouseapasswordmanagerandcreatestronguniquepasswordsforeverysite.Itisalsobeneficialtousetwo-factorauthentication(sometimesalsocalledtwo-stepverification)ifavailable.Forexample,youcandothisbyenteringacodefromasmartphoneappinadditiontoapassword.Thisisparticularlyusefulfore-mailaccounts,astheycannormallybeusedtorecoverotheraccounts.

Page 328: ASP.NET Core 1.0 High Performance

LibraryandframeworksupportTherehavebeensomesignificantchangesto.NETCoreandASP.NETCorebetweenRC1andRC2,morethannormalforreleasecandidates.Sensibly,manypopularlibrariesandframeworkswerewaitingforRC2,orlater,beforeaddingsupport.

Obviously,abookisabadplacetokeepupwiththechanges,sotheauthorhasputtogetherawebsitetodisplaythelatestcompatibilityinformation.YoucanfindtheASP.NETCoreLibraryandFrameworkSupportlistatANCLAFS.com.

Ifyouwouldliketoupdateanythingoraddalibraryorframework,thenpleasesendapullrequest.Therepositoryislocatedatgithub.com/jpsingleton/ANCLAFSanditincludeslotsofusefultools,libraries,frameworks,andmore.Wementionedmanyoftheseearlierinthisbookandthefollowingsampleisjustasmallselectionofwhatislistedbecausepackagesupportwillgrowovertime:

Scientist.NETFeatureSwitcherFeatureToggleMiniProfilerGlimpsePrefixDapperSimple.DataEFCoreHangfireImageResizerDynamicImageImageProcessorCoreRestBusEasyNetQRabbitMQClientMassTransitTopshelfNancySignalROrleans

Page 329: ASP.NET Core 1.0 High Performance

ThefutureAquoteoftenattributedtothephysicistNielsBohrgoes,asfollows:

"Predictionisverydifficult,especiallyaboutthefuture."

However,we'llhaveagoatthisanyway,startingwiththemorestraightforwardbits.TheofficialASP.NETCoreroadmaplistsSignalR,WebPages,andVisualBasicsupportshippingaftertheversion1.0ReleaseToManufacturing/Marketing(RTM).

Afterthis,itisfairlysafetoassumethatfeatureswillbeaddedtobringtheCorelineclosertotheexistingframeworks.ThisincludesEntityFramework,whichiscurrentlymissingsomeofthebigfeaturesofthefullEF,forexample,lazyloading.

Thereisalsothemovetowardsthe.NETPlatformStandard,toenhanceportabilityacross.NETCore,the.NETFrameworkandMono.Forexample,.NETCore1.0and.NETFramework4.6.3bothimplement.NETPlatformStandard1.6(netstandard1.6).However,youprobablydon'tneedtoworryaboutthisunlessyouarewritingalibrary.Refertothedocumentsatdotnet.github.io/docs/core-concepts/librariesifyouare.

Microsofthassaiditwilllistentouserfeedbackanduseittodrivethedirectionoftheplatforms,soyouhaveavoice.Evenifyoudon't,then,asthecodeisallopensource,youcanhelpshapethefuturebyaddingthefeaturesthatyouwant.

Furtherintothefutureishardertopredict,buttherehasbeenasteadystreamofprojectsbeingopensourcedbyMicrosoftfromtheearlyofferingsofASP.NETMVCtotheXamarinframeworkforcross-platformappdevelopment.

It'sanexcitingtimetobeworkingwithC#and.NET,especiallyifyouwanttobranchoutfromwebdevelopment.TheUnitygameengineisnowpartofthe.NETfoundation,andtherearesomeinterestingrecentdevelopmentsinVirtualReality(VR)orAugmentedReality(AR)hardware.Forexample,MicrosoftHololens,OculusRift,SamsungGearVR,andHTCViveareallunbelievablybetterthanthebasicVRthatcameoutacoupleofdecadesago.

It'salsoagreattimetobelookingatIoT,which,whileitmaystillbelookingforitskillerapp,hassomuchmorecheapandpowerfulhardwareavailable.ARaspberryPiZerocostsonly$5anditnowsupportsanupgradedcameramodule.WithacomputersuchastheRaspberryPi3,whichoffersalmostdesktopclassperformancefor$35,anyonecannoweasilylearntocode(perhapsinC#or.NET)andmakethings,especiallychildren.

FollowingthewisdomofAlanKay:

"Thebestwaytopredictthefutureistoinventit."

So,getoutthereandmakeit!Andmakesurethatyousharewhatyou'vedone.

Page 330: ASP.NET Core 1.0 High Performance

SummaryWehopethatyouenjoyedthisbookandlearnedhowtomakeyourwebapplicationshigh-performingandeasytomaintain,particularlywhenyouuseC#,ASP.NETCoreand.NETCore.Wetriedtokeepasmuchadviceaspossibleapplicabletogeneralwebappdevelopment,whilegentlyintroducingyoutothelatestopensourceframeworksfromMicrosoftandothers.

Clearlyatopicsuchasthischangesquiterapidly,sokeepyoureyesopenonlineforupdates.ThereisanannouncementsrepositoryonGitHubthatisworthwatchingatgithub.com/aspnet/announcements.Hopefully,alotofthelessonsinthisbookaregenerallygoodideasandtheywillstillbesensibleforalongtimetocome.

Alwayskeepinmindthatoptimizingforitsownsakeispointless,unlessit'sjustanacademicexercise.Youneedtomeasureandweighthebenefitsagainstthedownsides;otherwise,youmayendupmakingthingsworse.Itiseasytomakethingsmorecomplex,hardertounderstand,difficulttomaintain,orallofthese.

It'simportanttoinstillthesepragmaticperformanceideasintoteamculture,orelseteamswon'talwaysadheretothem.However,aboveall,remembertostillhavefun!