Race Report: 2019 Chicago Marathon

Date: October 13, 2019.
Weather: Partial Sun, 57F/14C with occasional gusts of wind.

✅ Primary Goal: Sub 3:30 (8:00 min/mile)
❌ Secondary Goal: 3:15 (7:24)
❌ Stretch Goal: 3:00 (6:50)
✅ Arrive at the start line uninjured
✅ Enjoy the day

Training: Pete Pfitzinger 18/55
Full Marathon History: None
Half Marathon PR: 1:26

tl;dr

  1. The Chicago course is flat, scenic, and extremely well supported.
  2. GPS is highly inaccurate downtown so don’t rely on it.
  3. Ran mile 0-22 perfectly between 7:10-7:30.
  4. Faded for miles 23-26 @ 8:00-8:30.
  5. 3:22 Chip Time for my first Full.

Pete Pfitzinger 18/55

Last year I used Hansons for two cycles to PR at the Half distance. While I enjoyed it, I needed a plan that had two days off rather than one. After some research and talking a lot to other seasoned Marathon runners, I picked the Pfitzinger plan.

Here’s a short snip of the start of the plan that I created to fit into my schedule:

Every week has:

  • (1) Long
  • (1) Tempo or Speed
  • (1) General ~10 Mile Run
  • (2) Recovery

Overall Focus:

I went into the plan running an average 20 miles per week consistently for two months before starting. I would not recommend the 18/55 plan for a person that is starting with zero mileage weeks, since you’re into 40 mpw by the 3rd week.

The first two weeks that were in the 40 mpw range hurt, as I was not accustomed to the training volume. Thankfully with this plan, once you scale up, there is a rest week that has reduced mileage. The same sentiment was repeated when I got into the 50 mpw cycles.

My appetite increased (second lunch or second dinners were becoming common), I needed more sleep, and I was seeing a physical therapist every 3-4 weeks to help massage out any tough spots in my legs. I kept weight training to one session a week with light weights. My routine focused on hip adduction/abduction, lunges, box jump routines, and resistance band work since I have a weakness in the gluteus medius on my left side.

One word — discipline. I missed one workout and I ran rain or shine. Period. That was the only way for me to chip away at the miles. The worst sessions were the Tempo sets in Chicago over the summer where the heat would get past 90F/32C. I resolved myself to getting up before the sun or wait until late in the evening to do any speed during the hot weeks.

The best sessions? I have to say that Recovery and the Longs. I needed to practice taking in nutrition, since I was coming from a Half background, so a no consequence Long run to test out food was a welcomed experience.

Results

  • 8 weeks out I ran a Half at 1:30 and felt pretty relaxed the entire time. I set the legs for 6:50 pace and just told them to go. After finishing I felt like I still had gas in the tank and that was a welcomed reassurance that my training was solid.
  • 6 weeks out a friend paced me for a mile time trial and I landed a 5:33🔥 for a new single mile PR.
  • On the longer 10k/5k tempo sets, I was able to hit the 6:30/6:10 paces pretty comfortably. Tempo is usually not my favorite of the routine, since you are working hard and pushing the lactic barriers.
  • First 20 Long crushed me, as in absolutely crushed me. I didn’t hydrate enough and whimpered home feeling that running the Full was extremely out of reach. How was I going to be able to add on another 10k to this?! A lot of self doubt began to surface at this point.
  • Second 20 Long was a major confidence booster. I had a friend accompany me for most of it, I was smooth and relaxed the entire run. This positive experience came from having a previous 20 miler under my belt and I took in more nutrition.
  • Last 20 Long, hard bonk. I started late in the morning, was out in the direct sun for most of the run, and didn’t bring enough electrolytes with me. At about mile 16 I felt cold, started to heavily perspire, heavy nausea yet thirsty, and my pace slowed to a crawl. I made the call at mile 18 to physically stop moving, drink as much as I could, and walked home.

Here’s how my paces ended up towards the end of the training cycle:

A few weeks out, I felt like the pace range for the Full was going to be somewhere in the 7:00 to 7:30 range. I wanted to wait until the taper period to make a final decision.

Expo

It’s huge and really well run! I took a ride share to the venue, got my race packet, and was out within 40 minutes. I never like to loiter around at expos as I feel they mentally drain energy out of me.

I went to the Nike Pace Team booth at the Expo and grabbed a pacing sticker for the 3:15 pace group. Done. Decision made.

Morning

Early wake up and got some nutrition in my body. For me the standard race breakfast is a bagel with a lot of peanut butter, a banana, and touch of yogurt with lots of chocolate chips.

I changed into my gear and had a little bit of race nerves, nothing too abnormal for what was about to happen. I took the Brown Line down to Library and walked over to the entrance gates.

Security

I did not bring a bag to check and discovered that there was an “Express” line for people with nothing to check. It took me about 15 minutes to get though the security line and on my way over to the Corral areas. I highly recommend not bringing anything to check at this race. There is so many aid stations with water/electrolytes that you really only need to carry your choice of food in your pockets.

Corral B

Submitting a 1:26 Half was able to qualify me for Corral B. Get into this Corral if you can. It is sectioned off and has a its own bathroom and warm up area away from the other corrals. Looking around the field, the majority of the runners in B looked to be in the 3:00 – 3:30 pace range.

Warm Up

Given that it was a chilly morning, I brought a throw away t-shirt that I kept on until 20 minutes before the start time. I did about a mile jog around the corral area, and was feeling pretty fresh. Just enough to feel a start of a light sweat is enough warm-up for me on a race as long as this.

My goal for this race was to arrive at the start line rested, settled stomach, and with uninjured legs. Three check marks for all of theses so I was in high spirits!

Countdown, 3, 2, 1… GO! 🏃‍♂️

Miles 0-4 River North / Loop

I had two goals for this section — go out at a conservative pace and not to obsess over the split times for the first few miles. I wanted to lock in a good mental attitude and cadence during the section.

The tall buildings in River North and the Loop make accurate GPS signaling impossible for the first few miles. At some points I was running a 5:30 mile, others a 11:00. Thankfully I’ve been running for long enough that I know that a 7:20 ~feels~ like, so I just listened to my body and ignored the watch.

The general mass of people started to inch ahead of me every so slowly and I had to not let that bother me. I thought I was really lagging into the high 7’s per mile, but from what I learned as the race progressed, the majority of people in Corral B were trying for times between 2:50 and 3:10. I discovered that the Nike 3:15 pace group started in Corral C, so I should have started in that corral for my 3:15 goal.

Miles 5-7 Lincoln Park

Marathon Guardian Angel — A fellow runner came up to me and asked me for my goal pace. Since we were both aiming for a 3:15, we decided to pace together. He was a seasoned runner and ran with me for 20 miles. We stopped at every other aid station for aid, shared stories, ate candy, and kept my spirits up. The miles just melted away as we ran together.

Miles 7-9 Lakeview

One of my favorite areas since I went to college in Chicago, so running around Lincoln Park and Lakeview brought back a lot of memories. This was one of the reasons that I was excited to run this race.

Half

Physical and Mental check — all systems green ✅

Given that I was running 45-55 miles per week and properly tapered, hitting the Half felt very easy and more like a regular jog than a race. With spirits high, I started the back half of the race, knowing that the pain was going to hit once the distance got into the 20+ miles.

Miles 14-18

West out on Adams St, down Damen Ave, and then Jackson East to Halsted. Had a small stomach stitch for most of this, but knew that it would go away eventually; I’ve run though worse. There were some sporadic crowds in the University Village area. From what people have told me, the support in the section has improved every year.

18-22 University Village and Chinatown

Once I hit 2 hours and 30ish minutes on the clock, I felt a change in my body. General fatigue, the lactic buildup in the legs, my heart and breathing rate increased. I knew this was where the real pain of the Marathon distance was going to start.

Miles 22-23

Just not fun. The support after Chinatown is lacking, the course tracks the Expressway, the cold winds were becoming more and more abrasive to my spirit, and everything started to hurt. I didn’t hit a hard wall or bonk, the additive fatigue of the distance started to chip away at me. I knew that if I listened to my legs and stopped, the rest of the race would be a difficult run-walk, start-stop experience. I did fast walk and grab extra hydration during this section and started a good shuffle between 8-8:30 pace for this section.

Mile 24 Michigan Ave

The penultimate section. The 3:15 goal was out of reach and I knew that I was going to land around the 3:20ish mark. A urban corridor of tall buildings, gusting chilly winds, and crowds telling you that the end is near. I was in a lot of pain, yet still had a smile on my face as I shuffled along.

Mile 26 Roosevelt Rd Bridge

Listen Midwestern people, this is not a “hill”. Yes, it is at the end of the Marathon so it seems like a insurmountable challenge, but it’s actually not that bad. I felt beat up from all the flat running, which is just so bio-mechanically taxing and wanted to give the bridge some effort. I actually enjoyed going up and down over the bridge at this point just because I got to change my stride a little.

Finish

Crossing the finish line was pretty emotional for me. The end of the training cycle, my first Full Marathon, and returning to my old stomping grounds to race. I was pretty saturated with endorphins after crossing, so I teared up a little.

The aid at the end of Chicago is very impressive. The finish area has many volunteers that are watching for anyone needing assistance. I waddled out of the area and took about 10 minutes to sit on the grass to collect myself.

Post Race

Lots of water, banana, and some electrolytes. I walked over to the Brown Line and took the elevator up to the platform. Eventually got home and wobbled into the shower. I felt hungry and ready to eat, which is a really good sign for me post racing. I crashed early and slept for about 10 hours the first night.

Reflection

I had to spend a lot of time running to prepare for this race, so a big thanks for all the people that tolerated my absence, me complaining about fatigue, and guiding me though rough patches during the training cycle. Though I was out running my race alone, the help and support of everyone was carrying me to the finish.

Would I do another Marathon? Not at this point. I want to take a year or two to switch it up and focus back on trails.

 

Site Maintenance with Arista eAPI

I started a public GitHub Repository in order to share some of my Python automation tools.

I work remotely on a large number of Arista switches and I have developed a script that captures the state of the network in order to run a comparison before and after network maintenance events. We have a monitoring system in place that alerts on various SNMP traps and events, but often times I need to interpret a number of changes via my network engineer lens to confirm that a maintenance period has been completed successfully.

The first Python script I’m publishing interfaces with an Arista switch over HTTPS and captures various outputs via the eAPI: inventory with serial numbers, vlan states, mac address table, lldp neighbors, routing protocol states, and route entries to a text file. A diff on the files can be run post maintenance event to highlight any changes for review.

This type of granular record can show that an item such as a metric on a route has changed. Our monitoring system does not alert on this type of change as it is monitoring the BGP peer status.

 

Link github.com/brentnowak/arista-tools

Portfolio Building with iShares ETFs at Fidelity

My employer sponsored 401k is with Fidelity and I recently tasked myself with building a long-term, diversified portfolio on their platform.  I’ve built out a portfolio that has a heavy weight in US equities, but also captures a large amount of both developed and emerging markets.

At the time of this post, Fidelity offers 70 commission-free iShares ETFs of various categories and classes, so I was able to pick and choose from a large array of ETFs in order to build out a portfolio.

Portfolio Tenants

  • Overweight equities given that I am in my mid-30’s.
  • Limited bond exposure due to rising rates.
  • High international exposure (~38%) to potentially outsize risk/reward outside the US market.
  • Keep holdings to less than 12 to ease monthly re-balancing.
  • Increase US Small-Cap exposure due to a belief that they will outperform over the next 20 years.

General Portfolio 

 

Addition of IEUR (iShares Core MSCI Europe ETF)

I found that IXUS (iShares Core MSCI Total International Stock ETF) and IEMG (iShares Core MSCI Emerging Markets ETF) did not sufficiently provide enough weight for my liking towards major European countries.

Adding IEUR (iShares Core MSCI Europe ETF) to the portfolio brought the United Kingdom, France, and Germany to an exposure level that was more in my risk tolerance levels.

Exposure percentage summary of each ETF by country:

 

* iShares® is a registered trademark of BlackRock Fund Advisors and its affiliates

Using Arista Telemetry to Monitor Network State

Arista’s Telemetry product allows you to stream network state in real-time from each piece of switching hardware to a central management point. Recently I’ve been waiting to prove out the visibility of the Telemetry product during a maintenance event. I recently had the opportunity when we were switching carriers on a transatlantic link between two sites.

The screenshot below shows a 30 minute slice of time where fiber optic links were brought down on Carrier A, traffic flow changed, connectivity was restored with Carrier B, and normal traffic flow resumed.

1 – Technicians disconnect fiber for the Primary Circuit at sites A and B.
2 – As the routing neighbor between the A and B sites drop, traffic is automatically moved to the Secondary Circuits.
3 – When optical connectivity has been restored between the two sites, the Primary Circuit re-establishes. Routing reconverges and traffic is shifted back onto the Primary Circuit.

Normal workflow for a change like this involves camping Syslog and the various switches involved, issuing commands to show network activity as the maintenance progressed. With Arista’s Telemetry product, I was able to see the state of various network components (light levels, interface state, bit rate, etc) all in a real-time display.

So far an impressive way to gain visibility into network state across a bunch of different metrics at a glance. I’m looking forward to test this product with my other future projects.

Race Report: Avenue of the Giants Half Marathon

Representing my home state of Illinois and Golden Gate Running Club

Elusive 90 Minute Half Marathon

After a disappointing attempt in February to run a Half in under 90 minutes, Xavier convinced me to sign up and train for the Avenue of the Giants Half in early May. It seemed really simple, but in hindsight this training cycle brought me up to a new level of running.

Trees Older Than Time

The event takes place in Humboldt Redwoods State Park in rural Northern California and follows an immaculately paved road through an old redwood forest. It took us about 5 hours to get to the race start given rest breaks, so not a quick drive out of San Francisco.

The entire race has you ensconced in a backdrop of redwoods so quiet that you can hear the birds chirping away in the forest. There isn’t much to do besides hit the turnaround point and double-back. Luckily for me, races in this scenery are a Zen-like experience and a welcomed break from busy city streets and intersections.

Doubling The Mileage

April was a big month for me, clocking in at almost 162 miles. Historically I’ve never run more than 85 miles in a month, so training for this race was a new experience.

Slave to the Spreadsheet

I’ve never followed a structured training plan before and Xavier helped guide me through the process. We used a slightly modified version of Brad Hudson’s Half-Marathon Level 1 plan with a few days switched around to follow GGRC‘s (Golden Gate Running Club) Wednesday Track night and Sunday runs.

Running ~40 miles/week was new to my body and the first three weeks of increased mileage had me in a rut. I needed to eat more, sleep more, and my water intake increased to around 2L/day. I had my general meals, but also started to eat when I was hungry. I successfully kept the snacking to whole wheat crackers with peanut butter, nuts, and banana & berry smoothies with yogurt. There was also a healthy amount of dark chocolate, which I basically consider energy.

The main weekly routine was (1) Tempo, (1) Long Run, (1) Speed Session, and (2-3) Recovery Sessions. I only missed two or three recovery runs due to work, injury, or travel; consistency was the name of the game for this plan and it shows in my Strava log.

Travel, Sickness, and Injury

Late March, when the miles started to add up, I had issues with my TFL and Hip Abductors. Every day, regardless of my workout, I was on the foam roller and Lacrosse ball for around 20 minutes a day to help loosen up tight areas. The diligence paid off and I was able to coast into the last month of training injury free.

The hardest block of time for me was the week of April 16-30th where I spend a week in Sydney Australia and also somehow contracted bronchitis. The 15 hour flight, jetlag, casual drinking, and inability to exchange air when running took a toll on me. Luckily I was able to find some unobstructed running loops in Sydney and log miles before the rest of my vacation crew wanted to head out of the apartment for the day. Additionally, my airway cleared up a few days before the race and my leg strength was unaffected. I knew at some point during the training block I was going to be sick, and I was just going to have to roll with it!

Race Day

I arrived at the start line injury free, rested, hydrated, and with a settled stomach — always a welcomed way to start any endurance event. It was slightly chilly and overcast, perfect running conditions. Since Xavier and I had the same race goal, we decided to run together with an agreement that if either of us was feeling strong and wanted to push pace, that we should go for it.

The limited GPS signaling meant that our watches were all over the place. My watch was generally beeping at each marker, but became more skewed with each mile. If you do this race, write out the mile times on your arm so you can see where you are at given clock time. The course it a basic out-and-back with a turnaround at the halfway mark. We clocked 44:45 at the turnaround, so we knew we had to maintain speed and start to try to negative split the race.

Around mile 10, Xavier started to pull ahead of me. My heart rate was increasing and my breathing became more labored. The rolling hills for the last third of the race started to wane on my effort. I found myself outputting the same effort as the first half (6:50 pace), but running slower (7:10-7:15). My heart rate was trending upward so I pulled my pace back by 2-3%.

Soon the sub-90 minute goal was out of reach and got weighed down with negative thoughts. When I accepted that I was going to clock in over my goal, I decided to enjoyed the scenery, cheered for other runners, and even ended up picking off a runner a head of me with a last bit of pain-cave-dizziness-effort at mile 12. As I finished, Xavier was standing right outside the chute and I could hear him starting to yell at me to kick my brains out – a welcomed voice after being in a pain cave for the last 20 minutes of the race.

I finished at 1:32:13, 26th overall, 8/71 in my age-group, and cut over 4 minutes off my last Half attempt. Overall a big gain despite not being able to clock in under 1:30.

 

Have You Tried Running More?

The post-race emotional high had Xavier and I recapping our training experiences and what I could do the next attempt to keep me from waning at around mile 10. For both of us, we needed more sustained efforts on longer runs. I was using GGRC‘s Sunday run as my long run, which meant running out to the Presidio (5 miles), idling for 10-15 minutes while the group gathers, running 6-7 miles with the group that included water/regroup breaks, and then circling back home.  The longer runs should have been constant efforts, which would have helped me dig deeper for the final third of the race.

This event was a big step for me, and I finally feel like I can brand myself as a runner. There is going to be another push to break the 90 minute mark, and I’m going to achieve it. This latest round of racing taught me more about my limits, what tools I need to be successful, and a few more tricks to improve the cardio system.

Cisco Live 2017

I’m back in San Francisco after a solid few days of conference sessions, heat, crowds, and getting to meet all sort of new faces. This year I concentrated on Nexus 9000 and VXLAN sessions as we are refreshing our TOR solution in the datacenter.

Attended Sessions

  • BRKARC-3222 – Cisco Nexus 9000 Architecture
  • BRKDCN-3020 – Network Analytics using Nexus 3000/9000 Switches
  • BRKDCN-3378 – Building Data Center Networks with VXLAN EVPN Overlays
  • BRKINI-2005 – Engineering Fast IO to the Network
  • BRKIPM-2264 – Multicast Troubleshooting
  • BRKRST-3320 – Troubleshooting BGP
  • BRKDCN-2015 – Nexus Standalone Container Networking

I also picked up a new addition to the library, Building Data Centers with VXLAN BGP EVPN.

Force-Directed Network Diagram with Arista eAPI and D3.js

2016-05-23_force_direction_1Overview

The Arista eAPI give you the ability to interact with a switch over standard HTTPS and return structured JSON. Here a section of Python code to populate a database table to automatically generate a network diagram based on LLDP neighbor relationships.

 

Requirements

Arista EOS
Python 2.7
Postgresql
pyeapi

Database Tables

CREATE TABLE report.control
(
  id serial NOT NULL,
  "switchName" text NOT NULL,
  "interfaceName" text NOT NULL,
  "interfaceType" text,
  monitor boolean,
  description text NOT NULL,
  "remoteSwitchName" text,
  "remoteSwitchPort" text,
  "lineProtocolStatus" text,
  "interfaceStatus" text,
  site text,
  CONSTRAINT pk_report_control PRIMARY KEY ("switchName", "interfaceName")
)

Sample Python Code

Populating our database table with Switch and Interface information.

import pyeapi
pyeapi.load_config('nodes.conf')

def control_insert_lldp(switchName, interfaceName, remoteSwitchName, remoteSwitchPort):
    try:
        conn = psycopg2.connect(conn_string)
        cursor = conn.cursor()
        sql = '''
        UPDATE report.control
        SET "remoteSwitchName" = %s, "remoteSwitchPort" = %s
        WHERE "switchName" = %s AND "interfaceName" = %s
        '''
        data = (remoteSwitchName, remoteSwitchPort, switchName, interfaceName, )
        cursor.execute(sql, data, )
    except psycopg2.IntegrityError:
        conn.rollback()
    else:
        conn.commit()
    return 0

for switch in switches:
 node = pyeapi.connect_to(switch['deviceName'])
 try:
 output = node.enable('show lldp neighbors')
 neighbors = output[0]['result']['lldpNeighbors']
 for neighbor in neighbors:
 neighborDevice = removedomain(neighbor['neighborDevice'])
 control_insert_lldp(hostname, neighbor['port'], neighborDevice, neighbor['neighborPort'])
 except Exception as e:
 print(e)

Getting a list of switches from our database table.

def network_switches():
    conn = psycopg2.connect(conn_string)
    cursor = conn.cursor(cursor_factory=RealDictCursor)
    sql = '''
    SELECT
    DISTINCT(control."switchName") as "name",
      site."siteDescription" as group
    FROM
      report.control
    WHERE
      "remoteSwitchName" != ''
    ORDER BY
      control."switchName"
    '''
    cursor.execute(sql, )
    results = cursor.fetchall()
    return results

Returning a LLDP neighbor value if we have one for each switch interface.

def network_lldp_neighbors(switchName):
    conn = psycopg2.connect(conn_string)
    cursor = conn.cursor(cursor_factory=RealDictCursor)
    sql = '''
    SELECT
      DISTINCT(control."remoteSwitchName") as "remoteName"
    FROM
      report.control
    WHERE
      "switchName" = %s AND
      "remoteSwitchName" != ''
    ORDER BY "remoteSwitchName"
    '''
    data = (switchName, )
    cursor.execute(sql, data, )
    results = cursor.fetchall()
    return results

Create a JSON string for D3.js Force-Directed Graph.

def d3_lldp(element):
    links = []
    value = 1
    nodes = network_switches()
    idCount = 0
    for row in nodes:
        row['id'] = idCount
        # row['group'] = 1
        idCount += 1

    for node in nodes:
        lldpswitches = network_lldp_neighbors(node['name'])
        source = node['id']

        for connection in lldpswitches:
            for row in nodes:
                if row['name'] == connection['remoteName']:
                    target = row['id']
                    result = {'source': source, 'target': target, 'value': value}
                    links.append(result)

    result = {'nodes': nodes, 'links': links}
    return json.dumps(result)